From 8505fa66b57768f75a26d146254493eea2423bff Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 15:12:45 +0000 Subject: [PATCH 001/158] Updates pom.xml to compile and test with success Updates HTTP to HTTPS repositories links Adds access-modifier-checker because the version is not specified in parent pom and maven gets the latest version which is compiled with a newer bytecode version Adds maven-surefire-plugin to pom.xml to disable forks and make tests pass. The current tests don't seem to be isolated and interfere with each other when running on the command line --- pom.xml | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b7c15eb1..2081a946 100644 --- a/pom.xml +++ b/pom.xml @@ -65,18 +65,65 @@ test + + + + + maven-surefire-plugin + 2.16 + + + default-test + test + + test + + + + + hudson.udp + 33849 + + + false + 2 + + + + + + + hudson.udp + 33849 + + + false + 2 + + + + + + + org.kohsuke + access-modifier-checker + 1.7 + + + + repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ From 2857007cdc7dcef31b115fa28335a24e9d09046a Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:22:30 +0000 Subject: [PATCH 002/158] Update url for project in pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2081a946..37d2448e 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ hpi Jenkins disk-usage plugin 0.29-SNAPSHOT - http://wiki.jenkins-ci.org/display/JENKINS/Disk+Usage+Plugin + https://github.com/jenkinsci/disk-usage-plugin From 5b70d2f3e5a2d6981edbef45872d5662b438698d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:24:03 +0000 Subject: [PATCH 003/158] Updates scm connection to use HTTPS instead of git https://github.blog/2021-09-01-improving-git-protocol-security-github/ --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 37d2448e..d5c2ff99 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ - scm:git:git://github.com/jenkinsci/disk-usage-plugin.git + scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git http://github.com/jenkinsci/disk-usage-plugin HEAD From 2fa9e4d35492b696e0b4e9d31d1dc1a4b496dfec Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:24:23 +0000 Subject: [PATCH 004/158] Use HTTPS in scm url --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d5c2ff99..9123da10 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git - http://github.com/jenkinsci/disk-usage-plugin + https://github.com/jenkinsci/disk-usage-plugin HEAD From af57af41524bcf9543c2e332f53b233df8d6a922 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:26:26 +0000 Subject: [PATCH 005/158] Removes distributionManagement that no longer works --- pom.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pom.xml b/pom.xml index 9123da10..1a8c2669 100644 --- a/pom.xml +++ b/pom.xml @@ -27,14 +27,6 @@ HEAD - - - java.net-m2-repository - http://maven.jenkins-ci.org:8081/content/repositories/releases/ - - - - org.codehaus.plexus From 62a9fd39cba284e7aef524dbda648ac1025cba9f Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:30:01 +0000 Subject: [PATCH 006/158] Removes unused dependencies powermock and mockito --- pom.xml | 18 ------------------ .../integration/DiskUsagePropertyTest.java | 1 - 2 files changed, 19 deletions(-) diff --git a/pom.xml b/pom.xml index 1a8c2669..45a6ffca 100644 --- a/pom.xml +++ b/pom.xml @@ -38,24 +38,6 @@ mailer 1.8 - - - org.powermock - powermock-core - 1.4.12 - test - - - org.powermock - powermock-api-mockito - 1.4.12 - test - diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 50d433e1..e38393db 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -40,7 +40,6 @@ import static org.junit.Assert.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.ElementType.METHOD; -import static org.mockito.Mockito.*; /** * From 33b6ab5e84a6134268f9af53245fa5080ec1b6c7 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:45:54 +0000 Subject: [PATCH 007/158] Removes unused dependency plexus-utils --- pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pom.xml b/pom.xml index 45a6ffca..636464eb 100644 --- a/pom.xml +++ b/pom.xml @@ -28,11 +28,6 @@ - - org.codehaus.plexus - plexus-utils - 1.5.15 - org.jenkins-ci.plugins mailer From 0165617511f5a72bf1e017703aa56d905c43d9b2 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:47:48 +0000 Subject: [PATCH 008/158] Adds escape-by-default to all jelly files https://wiki.jenkins.io/display/JENKINS/Jelly+and+XSS+prevention --- .../hudson/plugins/disk_usage/BuildDiskUsageAction/badge.jelly | 1 + .../hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly | 1 + .../hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly | 1 + .../disk_usage/DiskUsageProjectActionFactory/global.jelly | 1 + .../plugins/disk_usage/ProjectDiskUsageAction/floatingBox.jelly | 1 + .../plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly | 1 + src/main/resources/index.jelly | 1 + 7 files changed, 7 insertions(+) diff --git a/src/main/resources/hudson/plugins/disk_usage/BuildDiskUsageAction/badge.jelly b/src/main/resources/hudson/plugins/disk_usage/BuildDiskUsageAction/badge.jelly index 70dab1b7..a9e02df5 100644 --- a/src/main/resources/hudson/plugins/disk_usage/BuildDiskUsageAction/badge.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/BuildDiskUsageAction/badge.jelly @@ -1,3 +1,4 @@ + ${it.getBuildUsageString()} \ No newline at end of file diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly index b57cd3a2..a1e1dffd 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly @@ -1,3 +1,4 @@ +
diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly index 46e5d068..e8023152 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly index 8d22867f..711064c7 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox.jelly index e18e7391..bf778df9 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly index d1f3abb8..55b733cf 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly index 572ddb40..0497cb90 100644 --- a/src/main/resources/index.jelly +++ b/src/main/resources/index.jelly @@ -1,3 +1,4 @@ +
This plugin counts disk usage.
\ No newline at end of file From b442dee9dcdc097f85eb60e6403ab9320c5ad6bf Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:53:50 +0000 Subject: [PATCH 009/158] Removes usage of deprecated HudsonTestCase --- ...rkspaceDiskUsageCalculationThreadTest.java | 96 ++++++++++--------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index fe1078ce..f7cc3b71 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -4,6 +4,10 @@ */ package hudson.plugins.disk_usage.integration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import hudson.plugins.disk_usage.*; import hudson.matrix.AxisList; import hudson.matrix.MatrixProject; @@ -34,8 +38,10 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.HudsonTestCase; +import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; @@ -43,7 +49,11 @@ * * @author Lucie Votypkova */ -public class WorkspaceDiskUsageCalculationThreadTest extends HudsonTestCase{ +public class WorkspaceDiskUsageCalculationThreadTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation) throws InterruptedException{ Thread thread = null; //wait until thread ends @@ -79,9 +89,9 @@ private Long getSize(List files){ private Slave createSlave(String name, String remoteFS) throws Exception{ DumbSlave slave = new DumbSlave(name, "dummy", - remoteFS, "2", Mode.NORMAL, "", createComputerLauncher(null), + remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), RetentionStrategy.NOOP, Collections.>emptyList()); - hudson.addNode(slave); + j.getInstance().addNode(slave); while(slave.toComputer()==null || !slave.toComputer().isOnline()){ Thread.sleep(100); } @@ -93,17 +103,17 @@ private Slave createSlave(String name, String remoteFS) throws Exception{ public void testExecute() throws IOException, InterruptedException, Exception{ //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); - jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = createSlave("slave1", new File(hudson.getRootDir(),"workspace1").getPath()); - Slave slave2 = createSlave("slave2", new File(hudson.getRootDir(),"workspace2").getPath()); - FreeStyleProject project1 = createFreeStyleProject("project1"); - FreeStyleProject project2 = createFreeStyleProject("project2"); + j.getInstance().getExtensionList(RunListener.class).remove(listener); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); + Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(),"workspace2").getPath()); + FreeStyleProject project1 = j.createFreeStyleProject("project1"); + FreeStyleProject project2 = j.createFreeStyleProject("project2"); project1.setAssignedNode(slave1); project2.setAssignedNode(slave1); - buildAndAssertSuccess(project1); - buildAndAssertSuccess(project2); + j.buildAndAssertSuccess(project1); + j.buildAndAssertSuccess(project2); project1.setAssignedNode(slave2); - buildAndAssertSuccess(project1); + j.buildAndAssertSuccess(project1); File f = new File(slave1.getWorkspaceFor(project1).getRemote()); File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); File file2 = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); @@ -117,8 +127,8 @@ public void testExecute() throws IOException, InterruptedException, Exception{ } thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); - Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size2, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of job workspace disk usage does not return right size.", size2, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } @Test @@ -126,27 +136,27 @@ public void testExecute() throws IOException, InterruptedException, Exception{ public void testExecuteMatrixProject() throws Exception { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); - jenkins.getExtensionList(RunListener.class).remove(listener); - jenkins.setNumExecutors(0); - Slave slave1 = createSlave("slave1", new File(hudson.getRootDir(),"workspace1").getPath()); + j.getInstance().getExtensionList(RunListener.class).remove(listener); + j.getInstance().setNumExecutors(0); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = createMatrixProject("project1"); + MatrixProject project1 = j.createMatrixProject("project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); - buildAndAssertSuccess(project1); - MatrixProject project2 = createMatrixProject("project2"); + j.buildAndAssertSuccess(project1); + MatrixProject project2 = j.createMatrixProject("project2"); AxisList axes2 = new AxisList(); TextAxis axis2 = new TextAxis("axis","axis1 axis2"); axes2.add(axis2); project2.setAxes(axes2); project2.setAssignedNode(slave1); - buildAndAssertSuccess(project2); - Slave slave2 = createSlave("slave2", new File(hudson.getRootDir(),"workspace2").getPath()); + j.buildAndAssertSuccess(project2); + Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(),"workspace2").getPath()); slave1.toComputer().setTemporarilyOffline(true, null); project1.setAssignedNode(slave2); - buildAndAssertSuccess(project1); + j.buildAndAssertSuccess(project1); WorkspaceDiskUsageCalculationThread thread = new WorkspaceDiskUsageCalculationThread(); if(thread.isExecuting()){ waitUntilThreadEnds(thread); @@ -171,11 +181,11 @@ public void testExecuteMatrixProject() throws Exception { sizeAxis1 += getSize(readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1").length(); sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2").length(); sizeAxis3 += getSize(readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3").length(); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //configurations - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //project 2 file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis1", "fileList"); @@ -183,16 +193,16 @@ public void testExecuteMatrixProject() throws Exception { size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length(); sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis1").length(); sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis2").length(); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //configurations - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } @Test public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ - FreeStyleProject projectWithoutDiskUsage = jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); + FreeStyleProject projectWithoutDiskUsage = j.getInstance().createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); FreeStyleBuild build = projectWithoutDiskUsage.createExecutable(); DiskUsageProjectActionFactory.DESCRIPTOR.disableWorkspacesDiskUsageCalculation(); BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); @@ -206,10 +216,10 @@ public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception{ WorkspaceDiskUsageCalculationThread testCalculation = new WorkspaceDiskUsageCalculationThread(); DiskUsageTestUtil.cancelCalculation(testCalculation); - FreeStyleProject project = jenkins.createProject(FreeStyleProject.class, "project1"); + FreeStyleProject project = j.getInstance().createProject(FreeStyleProject.class, "project1"); TestDiskUsageProperty prop = new TestDiskUsageProperty(); project.addProperty(prop); - Slave slave1 = createSlave("slave1", new File(hudson.getRootDir(),"workspace1").getPath()); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); prop.putSlaveWorkspace(slave1, slave1.getWorkspaceFor(project).getRemote()); Thread t = new Thread(testCalculation.getThreadName()){ @@ -232,7 +242,7 @@ public void run(){ @Test @LocalData public void testDoNotBreakLazyLoading() throws Exception{ - AbstractProject project = (AbstractProject) jenkins.getItem("project1"); + AbstractProject project = (AbstractProject) j.getInstance().getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); @@ -249,13 +259,13 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ excludes.add("excludedJob"); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); - FreeStyleProject excludedJob = jenkins.createProject(FreeStyleProject.class, "excludedJob"); - FreeStyleProject includedJob = jenkins.createProject(FreeStyleProject.class, "incudedJob"); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(jenkins.getRootDir(),"workspace1").getPath(), jenkins, createComputerLauncher(null)); + FreeStyleProject excludedJob = j.getInstance().createProject(FreeStyleProject.class, "excludedJob"); + FreeStyleProject includedJob = j.getInstance().createProject(FreeStyleProject.class, "incudedJob"); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); excludedJob.setAssignedLabel(slave1.getSelfLabel()); includedJob.setAssignedLabel(slave1.getSelfLabel()); - buildAndAssertSuccess(excludedJob); - buildAndAssertSuccess(includedJob); + j.buildAndAssertSuccess(excludedJob); + j.buildAndAssertSuccess(includedJob); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); assertEquals("Disk usage for excluded project should not be counted.", 0, excludedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); @@ -266,12 +276,12 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ @Test @LocalData public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception{ - FreeStyleProject job = jenkins.createProject(FreeStyleProject.class, "project1"); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(jenkins.getRootDir(),"workspace1").getPath(), jenkins, createComputerLauncher(null)); + FreeStyleProject job = j.getInstance().createProject(FreeStyleProject.class, "project1"); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); job.setAssignedLabel(slave1.getSelfLabel()); - buildAndAssertSuccess(job); - buildAndAssertSuccess(job); - buildAndAssertSuccess(job); + j.buildAndAssertSuccess(job); + j.buildAndAssertSuccess(job); + j.buildAndAssertSuccess(job); File file = new File(slave1.getWorkspaceFor(job).getRemote(), "fileList"); Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(job).length(); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); From 42762e1986aec147704bf051c0df04cc0e0ac6f4 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 17:55:32 +0000 Subject: [PATCH 010/158] Use FreeStyleProject instead of AbstractProject in test Some java versions can not compile with AbstractProject --- .../disk_usage/integration/DiskUsageBuildListenerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index bf9465f2..4952ca6e 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -26,7 +26,7 @@ public class DiskUsageBuildListenerTest { @Test public void testOnDeleted() throws Exception{ - AbstractProject project = j.createFreeStyleProject(); + FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); From c5dfcc109157365b1ba514dd821056ff7d9e9a00 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 20:38:01 +0000 Subject: [PATCH 011/158] Bump parent pom (and Jenkins) to 1.587 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 636464eb..fa34a773 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.580.3 + 1.587 disk-usage From bfdcf2cda2b59351974328192343036e9aa6d377 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Jan 2023 20:55:46 +0000 Subject: [PATCH 012/158] Bump parent pom (and Jenkins) to 1.596 Removes usage of Run.ID_FORMATTER removed in jenkins-core https://github.com/jenkinsci/jenkins/commit/6d2e3ae5cbc57133ba2b46f19031957872ea74b0 --- pom.xml | 2 +- .../disk_usage/integration/DiskUsagePropertyTest.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index fa34a773..d8776eec 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.587 + 1.596 disk-usage diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index e38393db..f5985817 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -33,7 +33,6 @@ import hudson.matrix.TextAxis; import hudson.matrix.MatrixProject; import hudson.model.FreeStyleProject; -import hudson.model.Run; import hudson.slaves.OfflineCause; import org.junit.Rule; import org.jvnet.hudson.test.JenkinsRule; @@ -472,9 +471,11 @@ public void run(){ GregorianCalendar calendar = new GregorianCalendar(); calendar.set(2014, 1, 1); calendar.add(GregorianCalendar.MINUTE, count); - Run.ID_FORMATTER.get().format(calendar.getTime()); - diskUsage.addBuildInformation(new DiskUsageBuildInformation(Run.ID_FORMATTER.get().format(calendar.getTime()),calendar.getTimeInMillis(), count, 0l), null); - + diskUsage.addBuildInformation(new DiskUsageBuildInformation( + Integer.toString(count), + calendar.getTimeInMillis(), + count, + 0l), null); } } catch (ConcurrentModificationException ex) { exception = ex; From 3612902d3d58c5f9e5e538e9d802467772d53820 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 13 Jan 2023 15:05:18 +0000 Subject: [PATCH 013/158] Bump parent pom and Jenkins from 1.596 to 1.597 This requires migration of all zip files according to: https://wiki.jenkins-ci.org/display/JENKINS/JENKINS-24380+Migration bash script is included to document the manual migration that was performed testGetDiskUsageOfBuilds.zip required additional changes disk-usage.xml --- fix_zips.sh | 52 ++++++++++++++++++ pom.xml | 2 +- .../plugins/disk_usage/ProjectDiskUsage.java | 3 +- .../integration/DiskUsagePluginTest.java | 6 +- .../integration/DiskUsagePropertyTest.java | 22 ++++---- .../ProjectDiskUsageActionTest.java | 3 +- .../testDoNotBreakLazyLoading.zip | Bin 46785 -> 38558 bytes .../testExecute.zip | Bin 18488 -> 16774 bytes .../testExecuteMatrixProject.zip | Bin 30695 -> 28476 bytes .../testBuildInfoIsNoLoadedMultipleTimes.zip | Bin 8075 -> 7344 bytes ...oLoadBuildInformationWhenBuildIsLoaded.zip | Bin 8075 -> 7344 bytes .../testDoNotLoadAllBuildsDuringStart.zip | Bin 47297 -> 38576 bytes .../testNotBreakLazyLoading.zip | Bin 47297 -> 38576 bytes .../testBackwadrCompatibility1.zip | Bin 47235 -> 38553 bytes .../testBackwadrCompatibility2.zip | Bin 48315 -> 39074 bytes ...ckWorkspacesBuildsWithoutLoadingBuilds.zip | Bin 47961 -> 39112 bytes .../testCheckWorkspacesWithLoadingBuilds.zip | Bin 48765 -> 39451 bytes .../testDoNotBreakLazyLoading.zip | Bin 47276 -> 38576 bytes .../testGetDiskUsageBuildInformation.zip | Bin 47297 -> 38576 bytes .../testGetDiskUsageOfBuild.zip | Bin 47297 -> 38576 bytes .../testGetDiskUsageOfBuildByNumber.zip | Bin 47297 -> 38576 bytes .../testGetDiskUsageOfBuilds.zip | Bin 47297 -> 38575 bytes .../testCalculateDiskUsageForBuild.zip | Bin 20561 -> 18559 bytes .../testCalculateDiskUsageForJob.zip | Bin 21249 -> 19211 bytes .../testCalculateDiskUsageForMatrixBuild.zip | Bin 31969 -> 29570 bytes .../testCalculateDiskUsageForMatrixJob.zip | Bin 33097 -> 30806 bytes ...rojectWithConfigurationInSameDirectory.zip | Bin 54979 -> 52941 bytes ...tCalculateDiskUsageWorkspaceForProject.zip | Bin 11904 -> 11904 bytes ...spaceWhenReferenceFromJobDoesNotExists.zip | Bin 54979 -> 52941 bytes .../testExecute.zip | Bin 21249 -> 19211 bytes .../testMatrixProject.zip | Bin 33337 -> 31046 bytes .../testNotToBreakLazyLoading.zip | Bin 46785 -> 38558 bytes .../testAllInfoLoaded.zip | Bin 47073 -> 38558 bytes .../ProjectDiskUsageTest/testFirstLoad.zip | Bin 50227 -> 41664 bytes ...AllBuildInformationFromPreviousVersion.zip | Bin 47428 -> 38866 bytes .../testDoNotBreakLazyLoading.zip | Bin 49300 -> 40471 bytes .../testDoNotCalculateExcludedJobs.zip | Bin 10411 -> 10411 bytes ...estDoNotCountSizeTheSameWorkspaceTwice.zip | Bin 7595 -> 7595 bytes ...ageWhenPreviousCalculationIsInProgress.zip | Bin 11904 -> 11904 bytes .../testExecute.zip | Bin 11904 -> 11904 bytes .../testExecuteMatrixProject.zip | Bin 39178 -> 39178 bytes 41 files changed, 71 insertions(+), 17 deletions(-) create mode 100755 fix_zips.sh diff --git a/fix_zips.sh b/fix_zips.sh new file mode 100755 index 00000000..6664f074 --- /dev/null +++ b/fix_zips.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# TO CLEAN +# find src/test/resources -name \*old -delete +# git restore src/test/resources/ + +for ZIP_FILE in $(find src -name \*zip |sort ); do + ZIP_FILE=$(realpath $ZIP_FILE) + echo "$ZIP_FILE" + + TEMP_DIR=$(mktemp -d) + unzip -q $ZIP_FILE -d $TEMP_DIR + + OLD_ZIP_FILE="$(dirname $ZIP_FILE)/$(basename $ZIP_FILE).old" + mv $ZIP_FILE $OLD_ZIP_FILE + + find "$TEMP_DIR" -name "*~" -delete + + for PROJECT_DIR in $(find "$TEMP_DIR" -name config.xml -not -path "*/axis/*" |sort| xargs dirname); do + echo $PROJECT_DIR + DISK_USAGE_FILE="$PROJECT_DIR/disk-usage.xml" + + BUILD_NUMBER=1 + for BUILD_DIR in $(find "$PROJECT_DIR/builds" -mindepth 1 -maxdepth 1 -type d|sort); do + OLD_BUILD_NUMBER=$(basename "$BUILD_DIR") + xmlstarlet ed --inplace \ + -u '/build/number' \ + -v $BUILD_NUMBER \ + "$BUILD_DIR/build.xml" + mv -v "$BUILD_DIR" "$PROJECT_DIR/builds/$BUILD_NUMBER" + if test -f "$DISK_USAGE_FILE"; then + xmlstarlet ed --inplace \ + -u "//hudson.plugins.disk__usage.DiskUsageBuildInformation[id='$OLD_BUILD_NUMBER']/number" \ + -v $BUILD_NUMBER \ + "$DISK_USAGE_FILE" + xmlstarlet ed --inplace \ + -u "//hudson.plugins.disk__usage.DiskUsageBuildInformation[id='$OLD_BUILD_NUMBER']/id" \ + -v $BUILD_NUMBER \ + "$DISK_USAGE_FILE" + fi + ((BUILD_NUMBER=BUILD_NUMBER+1)) + done + if test -f "$PROJECT_DIR/nextBuildNumber"; then + echo $BUILD_NUMBER > "$PROJECT_DIR/nextBuildNumber" + fi + done + + pushd "$TEMP_DIR" + zip -q -r $ZIP_FILE . + popd + rm -r "$TEMP_DIR" +done \ No newline at end of file diff --git a/pom.xml b/pom.xml index d8776eec..7c188d06 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.596 + 1.597 disk-usage diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 7822737f..16061462 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -93,8 +93,9 @@ private int numberOfBuildFolders() throws IOException{ int count = 0; if(file!=null && file.exists() && file.isDirectory()){ for(File f : file.listFiles()){ - if(!FileUtils.isSymlink(f)) + if(!FileUtils.isSymlink(f) && !f.isDirectory()){ count++; + } } } return count; diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index a890be82..48e9ee59 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -81,7 +81,7 @@ public void testDoNotLoadAllBuildsDuringStart(){ @LocalData public void testDoLoadBuildInformationWhenBuildIsLoaded(){ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuild("2013-08-09_13-02-26"); + AbstractBuild build = project.getBuild("1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Build should be add after its loading (if it is not present before).", property.getDiskUsageOfBuild(2)); @@ -92,12 +92,12 @@ public void testDoLoadBuildInformationWhenBuildIsLoaded(){ @LocalData public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception{ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuild("2013-08-09_13-02-26"); + AbstractBuild build = project.getBuild("2"); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); j.jenkins.reload(); project = (AbstractProject) j.jenkins.getItem("project1"); - build = project.getBuild("2013-08-09_13-02-26"); + build = project.getBuild("2"); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Should be loaded build 2", property.getDiskUsageBuildInformation(2)); assertEquals("Only one build should be loaded into disk usage build information.", 1, property.getDiskUsageOfBuilds().size()); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index f5985817..f295de62 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -253,7 +253,7 @@ public void testBackwadrCompatibility1() throws IOException{ DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); property.getDiskUsage().loadAllBuilds(); assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); - assertEquals("Size of build 3 should be loaded from previous configuration.", 23932L, property.getDiskUsageOfBuild(3), 0); + assertEquals("Size of build 2 should be loaded from previous configuration.", 23932L, property.getDiskUsageOfBuild(2), 0); } @@ -291,8 +291,8 @@ public void testGetDiskUsageOfBuild(){ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild("2013-08-09_13-02-27"), 0); - assertEquals("Build with id 10 should have size 10000", 10000, property.getDiskUsageOfBuild("2013-08-09_13-03-05"), 0); + assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild("1"), 0); + assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild("7"), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); } @@ -302,8 +302,8 @@ public void testGetDiskUsageBuildInformation(){ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageBuildInformation("2013-08-09_13-02-27").getSize(), 0); - assertEquals("Build with id 10 should have size 10000", 10000, property.getDiskUsageBuildInformation("2013-08-09_13-03-05").getSize(), 0); + assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageBuildInformation("1").getSize(), 0); + assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageBuildInformation("7").getSize(), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); } @@ -313,8 +313,8 @@ public void testGetDiskUsageOfBuildByNumber(){ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild(3), 0); - assertEquals("Build with id 10 should have size 10000", 10000, property.getDiskUsageOfBuild(10), 0); + assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild(1), 0); + assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild(7), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); } @@ -333,10 +333,10 @@ public void testCheckWorkspacesBuildsWithoutLoadingBuilds() throws IOException, } @Test - @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml, jobs/project1/builds/2013-08-09_13-02-27/build.xml, jobs/project1/builds/2013-08-09_13-02-28/build.xml") + @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml, jobs/project1/builds/1/build.xml, jobs/project1/builds/3/build.xml") @LocalData public void testCheckWorkspacesWithLoadingBuilds() throws IOException { - File file = new File(j.jenkins.getRootDir(),"jobs/project2/builds/2013-08-09_13-02-26/build.xml"); + File file = new File(j.jenkins.getRootDir(),"jobs/project2/builds/1/build.xml"); XmlFile f = new XmlFile(new XStream2(), file); String newBuildXml = f.asString().replace("${JENKINS_HOME}",j.jenkins.getRootDir().getAbsolutePath()); PrintStream st = new PrintStream(file); @@ -403,8 +403,8 @@ public void testDoNotBreakLazyLoading(){ int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This tests does not sense if there are loaded all builds.",8>loadedBuilds); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Size of builds should be loaded.", 1000, property.getAllDiskUsageOfBuild(1), 0); - assertEquals("Size of builds should be loaded.", 7000, property.getAllDiskUsageOfBuild(7), 0); + assertEquals("Size of builds should be loaded.", 1000, property.getAllDiskUsageOfBuild(8), 0); + assertEquals("Size of builds should be loaded.", 7000, property.getAllDiskUsageOfBuild(4), 0); assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index e6fd4077..324da2b5 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -202,7 +202,8 @@ public ProjectTestBuild createExecutable() throws IOException{ public ProjectTestBuild createExecutable(Calendar calendar) throws IOException{ ProjectTestBuild build = new ProjectTestBuild(this, calendar); - builds.put(getNextBuildNumber(), build); + build.number = this.assignBuildNumber(); + builds.put(build.number, build); return build; } diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest/testDoNotBreakLazyLoading.zip b/src/test/resources/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest/testDoNotBreakLazyLoading.zip index e9a35ad0c9ca91fe1cfda9aaab27ebfbba9be6ab..0d9178a8e2097d286889b288faa95f312aae3528 100644 GIT binary patch literal 38558 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 L9L@$x9EbBC&LWQZ literal 46785 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 diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest/testExecute.zip b/src/test/resources/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest/testExecute.zip index 4287ce5c5d3057ed6b1122242cfd76cb50b21648..10d2f48051c0694e424c4aab03c67fe40b54f299 100644 GIT binary patch literal 16774 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 literal 18488 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 dAf6YfHOtB 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 B$OQlZ literal 30695 zcmeHQ2|QG5*dN)qNY*R~WwMVb5?RWYU6PctQ(3Yl?U9N?ilpmWO3HF8w22m>l(n?b zMOtlcz_uD0r*-)!`QOb z$9*&!R!FguissL%tGy2>VfOXhy7W4|r=3nIaew(t-Z~X|Ub(G0=I^7eM2gpG_p~*} zdUap!X1zVP<3?wM$T`VY`)B0`UZljC+PH`&m`1y8_;Pi`#-{3s^G_yg|5C?OY`n@2 zgK7>;1?n{(S{5$~Z@YdqW_@titY18SPB>24Pm#Y@bGe6VW~v&4#g__kt`Wc6Nt=>$ z&llmaLDFqkw#}8x)wtQQuH~}+F*mcFN2`oFtP@kQx_>97xLg-t)mm~bGCn&yo}aZW zlAj0n+Th=z5>6+dTg?_Yp!@8=rQ+r3xcZ1J3)kb9=psek@4tMl{$QJy*(}W|+V3}0s zlH%7MJ57fDjx6qP(8qZmFZA1W`(f_z;9okCl5sm_H)pgBGKSJeoLtYosx^4zMVRna zB`f=q_VVn342v+1rGgh-1#@=R{-q;O+FA8d-bPpA(A9;rPM$j0#CA8=ulWRLyH_e} zfxooe3dS%^>pQKXtcQ2&^hx*D+egpL3h@!cB%eQZ%C>Q!z(r2dZh;kRTD_gds~Dr? zBCGm!t$g9$4$imwITG!HZR(3HwK<~1s<|e7pwF69kEx(o&=7FS>%f-<4SfKg4^2G% z14e!FQy0mgvFdS!QD3>7Ld&Ca^N+?=h83&K8FPDO{QPgk8ZYvoZ(b-XK38j^t;$NKy3#=^5uyD1Rp|bXtgefeBY`WP zbqvUFlGEOrc^PJEE36SAb>>4XF!LOS^>E2E&1DFdMzKosHeARMWX|tb7fOm>U=Zh4JiDoGm)@ZnLjHC4bV`SV zEsy76AI<5%n%Z!^B2rcOWRz{Cx}$Fe$3^}%J;&^HGY&ZLUz}H-qqw??YiP-l)F+)D z`F9>j=5y`fd~GW|ki{3e_f^U3nm6+t@62Lie&yV7YE}NW=ZhnZBHzWm{kk%~vGOCw zI+2V2+FNcf8ClbB5DKixD;V-PiV5I@j6z z{~VMmx{(mn6YL&2DgiJU4y$+y}=cb(mg$*Xn9(I^EU1?zpg;BImVd z&LbAHw7tVhQgh6b6>nv1ZuYw1cCUOmO1SW0>ML&DOPGEZehaBP49y!7zG$D}TYfrc z5&wF_%jGZqO>a0gU4MmR^SNwhGQuA>q*mzd&gDMfouF`&(JVIR?>@E_wfxJD6e)in z5=rOzIP0^=?HXog6L*%0RoV#h5cTInZqPAwf-HBAocS83|_3tqk zgr1Myc(+(@nUrvI_cn1ip@-i;#oa$6bSwJ&tnHY+3|trJ;^?}(pC}&=y6>JR{c*qU z0WaybmB(^p2mP0dmI4 zg1sx91DDf@HPWkdKfGzd^k7a%+pG8uBN{fswhG4POQN*bU;n|#C-TfxG}Dkl(D?jw zt*7sG2Tz8?r$mRUF3Y)bLDQ&Pz&PJLxu2*F0F6nDVQZd(?DIRS9@NC9qvD}~)_zY1 z8-><>Ul|4^M^XO!FMN$+V$O_}XhHY~X>BrcwBCy>1S&v! zqx}aAfGpa`fWgQi$p(bBUM1;MqQ<9>y$@*fGQBRk^g6tV{ay`&$$F);s=U52`>(Y| zoVhQ4y~20a-?s}qoD&ngg@3-cOX^;(euH)Gi4t8k7J2goB~6)?bL6gW@mRVjwO^E5 zMv=}#H?wYb(?By0Z1Qr0lR!OZ2_99I0CVKuA zvFZ`-Pm;BT-(+^-QeMr@`~3Q4WUG@y$&MM@N}1>D=cLZQ(=?B_?Vl|B#7o2WhlZFg z=3iBK%O3a4bW4bzw2YIcK12Ac!h?2uUj<%G6f2d$X8B<=M^B|3ewf@IZCa2% zT7m|K@#`3*ZfuZl_RWA-l+d#yyo+Fk&twGwE+Pdq`;?Km2)LVvcN7wcyRBB4&%klt z9+q9aUhT?T8B4D85^htIqlw}UrfpG|YrK{u@ju_|bBn9QKrQfg_nFgGk)|D1^EL8U z3u+3vwGAri$eTK}K6AMdTr{_lBjfwgxZ?UWG5Ou8etY8aXG0R$hKaMGMJ=p8!bNeR zp+`mfJ~to!R(qgE>mBDlJt>hx%4&VHL(gU=^uOnkuNDkgBPAbe8&xfkSKqj+D&@ZA zqar@j^PS&6MBJm(H~r_}{D49sL+r&+%La)x(Qc*7!z5g4?qf?mZvqXu-Zd`Y%DgY~ z@Tg~-9!V*b>s^D1j~f>8vhZOyt+}()ai0F&GC5Y6EsL=mm<~yGzS^35{p*e`0*~?n zmfh|;^!!BaF_+VZ^A9fw^-kN5Z^z|bt&!!BFDw!JglV7~J>7|1aqP~L=6?-_BCg)b ziM*e7nt#6Etc1%4J^H_!VSm0A!!^#$8naTG7O!^#R=aEGv3( z{tj->TDIptTqAMstWQ3VQDR#5t;>%rnG1qTpTEnoIrmjJ$Yk0|-(pWL3i*HcR`STCSG zGQcFMbtelmr(lk3t(SZC8!6S<#fNJnHU#dJlM8NShIkyK|!6*Ubok__nJisZ;7v$OLkj$x*@aduTyq`14(kZafY8;g>zQK zp2v15Wc$_aS8%wZx?>ApTVc%Ko{htb8gg~p$|QfB891}r#5*fw-*z6YvnvtFjysFPr zGpY{qIZERu*vz)Ie#I|b&-p5g{MPjx6#*@bHi|KqcA3loDhK?RD9r!8U4sKgD-yFnFDF;O z(R*8uNpItoiAoaup~my1S%E%4IpPWI1qERbCUGJ}^8Ut6E8s-v(^tL)j2ADf&2fuK zY7tzDRSREt{M3pS@nKP$e*7ILvO{^MZN|5zF8j6|(~lcuBRSVf=V!V}zwgP$lm<%H zmjtDJSN#?jbh9}}ZJg5k9aVNN|7xA>lfnl>>%YuQ=z zL!z=R8ke%ov%!vo{cKmBs^h$a_MB=L72|~#SuDO_5X_a3x5;YHhk*yZVX?JyzcNnL zluSUG!f?X&z)Qd@@V9rM2810ualB_Bbu{7{V`^R^&K(X^jxLIt_3f4PuCreRKMkGR zW8&DE#`}-WK#UJZgpJ$pWLgf81t?XVtGUaFM8q%lxdJi%i_LU{kDzLxfDnwk0w zjwWx)-5eIv;G$rChlSmxCcPb7|8tG%$PB}8G2&~(mx}kLYVPm+Ie4{V5zi*Kn`z}0 z#lfa3B2}eU9HJVH);&Mo_Xe-k&_DF?f_vN*r6B9a_eI)jLmTzG3c`gNReGKX|17?> z^4|np!U2|f&3qrX-`#j?&4Uo9st{aUt;W*s5TjSr*Kh zYz-+Zl3GLIq_+hsqibkvah~+#)C06X{>yffHAI84oY7^S0hE#?CUPbug%Vmj4TK08 z9~~oFURC|mm?$g$7M;L1i?C@fv`h?X=r8DWu?#5#f)k8xy!=sG0Df<0irW$dRKh1Z zVG*jEtl`lyP(iA0s?@BC6pcFdA{1_1z35blP&h*Ah<2%}!F2h{G^9=p2zsQ-dg^Ep z3CQSl3WXdu(YTOA%})Xp;S(JsRIe04Ql(dUm|mv{KIjBP2!qxy5yC7&8L^>VoAGwY zxM#qUBJTG=p;aDKDvF#Bojag_nl`D3J8WaC7cG=DBM(e!x*55e@_V+iqHg@V{*WZ_?LN*3>g!LM#PtK!0R%I8Ii8Y5`tW^AV+O1CBR=_L98ow7TQr8 ztz5=tZl)87h09N=*b|mdcI)CbbShXN!MMyorYC6wbA|7O;6HV4xDJSg+p;~9)xqjkxwr(cvs3BTs@KJMO zS`OT_qXk-L_`!1o>uf2=!9`{vVuc%@NkzTD!1y<*!KWyJL91Xe{yH8+@)LGFRFoZH z{9$VFf%_;xoW;M&5P|(QLH19W4VC{_040^72|ESXU_DU80jVkAei;Xf6PbAI&8rIn?rtK`VfN4iub%6@WSb zgRw86#il6ul9$^=7_r<`Y^uO=zekHr1Gx`~faRuWrPIjX!lEd#DUur+Wx+bXfgGEP zL<`2Y5ko9D&3vtEDs18w|5#?DncR_cr;vLxY>J8t_*^D&P?Zt~W0T!G61FAy;X9I% zl=Su=Y~|W{2oMqPJK!UR#L^l_Aiy3C@Z%f!No5|}DnmE$I8gRjD1`tQA4Sma&?P{y z|H5DiH5t;H1R69XK{$@{q2dv62%i+!U-0oWV*7PKfXGH=kRC}4qK)<8$6OXZ=`#U4 zvOjGBSU$3_aF@jolaX02@F6l{Y(Z%R*n|a&A1Nb=IOeSIaWG=UyGRhhiv&L$MiQ42 zEq}vKAt`YfM4;s{nc-7a#4>vUZ?-3{EnyZW#sp>^Q{MiY|e z?>CV}fCySb_;DkWf{rN|T1SFIQ3ni`5E^J3ihSju;t_BNpA?58s6fJ?m^TCgqCwjQ z3=jjW0RS2B<1}Pe9(m4nH%2fZSRTIjjm;ep-+t#KFRGK&rM1rR_f?Qv60EB# zWUOHI2mB}IpkrkS@~^dvX{ReRI$8!|(}0u>!IgiN5NH?>`nzKuZLtKQJ_rm5pJ*t6 zP4WO41+tEUhK&lyBt~io6+(q6R6)qsks?!L0De{=m=t6-S zNZ<5Jp+f&MB?YHUXarXWp$DQtr^e!7_*Mw~xJk!_Cv&!hMtZRB?KQxkl_n3; zeI*2a$|3`ez+gy~Wnh7)fJEotV8}DbAn|h{$a6lS>o=B7W@tjCq+m%=59@^-7M+5@ z(!PYiQsl(cORJ{^Rx$;!w2=0nsbGm4M$|-UY0z2~S`L<$%)&vV+Jzvn5EvL4|3w2Q z3W95d!4U#H6`@WH1fil0RUZL@@JWdn@ClT$J?q%2KMKJh>yV>x_<0lrTSTytx~GC8 zc0@{~gKn3>MzYcYYjC0?LNg;>oD>3yk;scdrwbMXwvNzfiVx&#Yhe&nXow&5=nUAS zsnHDh+21C4HoBk*R*3;HxJBI39A6q}v<;>m4|_BlXHNboM*Pna#B2fn69M{OSAqWlgZUrv=||`Q diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePluginTest/testBuildInfoIsNoLoadedMultipleTimes.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePluginTest/testBuildInfoIsNoLoadedMultipleTimes.zip index 6643ddcfd363a294b556c96a590bd55644136287..7a066ba501dd5a3c97877510a61e146215ef043c 100644 GIT binary patch literal 7344 zcmWIWW@h1H00FNA-7qi%O0Y7>Fl6N?73+tFa56A^dmKy#;nE6j21b^b%nS@*A^@j$ zKA84`qWrAXT0v8W_9MIotD zp|m))NFgyVKd&-3zqFVO95tDF=?a;73g!7l*~JBk$*Ej!nR%JT8L25&3c;by&aT11 z;Fu8sx`6|n@~(OE+&K#5r86=xDByM#IEvuD#*rv%Cm8ZK83?qN*Rdu}f3@UrWKxHk zni}7U94_055mA>HADf@wogvY4yY~CLuj}|Xr7wTP9+lM_r`}yM@5qX5<>CV$#8 zd+nqi_kf*Yo^nSGJ9d3vERy9Pu72{x7Gt5%S={bBB)@Eb!~W{RV*Y<6bJA58-aXBD zEVF~}u7-z?@-YON1+Q(oPwlH(zoL7~B&wg&xXy}zudAUX+E~@IZcvDb(tLmGd z6PoQajwsv}c+Y`ojg(jdWeH-y(&>rBEDBVh1&0q z;7QBON%hGrE&<2frhlB+V$NIZ>>1CCt52MLcYjVoX&S-7BlDq{kMn{ zZ{mj;4DzcH*rSFIu_n>a9%oOU4A(fXf66nEg|VOUSuyVxW;a=rR|^8!d#y4S$QnRd zR~%!&euOyXMi!^@tXnVkY66{d7MKz7YC`^()!ip!Tah5NHgBVi2 z6J5R->C?V^G18}V`Lfp~CF>Y4M)8&}M*2jSFOJ-Y40u}K|LfYgySwV5^O_R@0xbN+ z=_|9ZBwqL0++}~i%1Fmu=l+|Ko`fMmu|7G1&S2 z*rxR7cFTuSQK|bfCp$Tv;*Ty<{{QciyU59dY!Vqxz|Kixkf?js;kwquoBCb z=Bl1cQ(tV`nqD|*7U#p>z^=%x*1~m77oLA(K@>25fd$O9yT%Uo!0?$2#5i-ckv>WR z^NySXrp+Kqe(wBfGbeYQGH&`j$>EvU;_RcVII{RUzMRz2d&q<*3*d1VBqtJE)uI<; zYPd>NBYl{`M79mE7a`h2n-2XjrUmaPci4tUv$>J;jQ2==C~I^p<%r2}v&kE7jz z$WiFknGW$5&?@NJfK5M^$>B{mfEm0J*vOK=a8h!9URoxiNy+n+B?wECGIfHl{}Ba& zw)cNUQ}k_bzBrhl0{zE4ny zXtPrIy3n@q&HtZU&ln3Or0raE^30(MUlW;gM}v4|t?veZ{P*-rMTE6m`|}m)Q#Trv z1)n}F^YUWzUAK3;+9dCqe7q$6|IlvNJ2MPtG;t{27kyrSAbxk)@v5YARfbb9T3fxZ z^1L6od`r}(`};TkWW?Rb5yJ>6ViN=Q)P~ukftg29A)|!TnNVZtQMO3qbOf!^HF|Rm zzYAzxlE~roKP-;PD?pS9noI5QWn_|L#-4szfn^5-2r&G01hJsQ1gwx@0<=D8fH!WV z_)v@jwLic{Aq^Q2XC~@^0mOO0GLB(OV>^bK7{dp|SphT$4n$F${QxMA>TGyECf#Up z6r=Tlp1^7}sHH>LaLgt@B53|LHsCfKtpfnG2{gcfCt@)N7LaXvg4-r=HvnipXqW-3 z`H(gYsKtglM1X956>y*kM=*h-0y1ELFT5bOVD_{Twrpvf2^{poVGAhpLHgZ5OF;c@ ztX{#Mo#atsT!jUvC6E#X)ZHWO6Z8g%3e*xvrl=)s3A8u?+63xdWAzU9wl1no9IOPr z1F{KNECX!ggxL;vr0cMn+OFM#Blssxv(JdIWlQ5PcAUOI$ts{8BndH&npGxo;Isr$+2YG8*prnSN`8Dz z*b<^jd+eD-8zozM0|&lv#68SIP`il8GY|{$mjgEmTS%pHAO#rK1iVIspRh-mI%4P0(8~%ZLt0%#Ipz&bp6bBXYM5nA$-B97<%E n^5gOWaS@I^l$23Ish6M~1VW1ySXY5&gA^E=c^DYP1wcFinPT9~ literal 8075 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 literal 8075 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 UCt`kWVgC2hLnPY8h!cta2h6RE`Tzg` literal 47297 zcmeHQ30RG38$P5_gi4x}QW05Fr%hTIZKOygsYz)$rBK=^#6*^|GiGd!A=^}DCbCQj zO%Y0yCL=S2jL_H``x5{Aozpqrdd~U2@4V+s|NoD<&XntNefM+U&+|U-^DgK4CVMJ% z(c*A8Dx6nIsxE)@%jKAXzwJ@wa7J_babn}clg#HP#>es^k}b`{Q(|UECYf7WaIMTN z?98|pp~x?mW|p?*Nh#rxF^OE!�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 UCt`kWVgC2hLnPY8h!cta2h6RE`Tzg` literal 47297 zcmeHQ30RG38$P5_gi4x}QW05Fr%hTIZKOygsYz)$rBK=^#6*^|GiGd!A=^}DCbCQj zO%Y0yCL=S2jL_H``x5{Aozpqrdd~U2@4V+s|NoD<&XntNefM+U&+|U-^DgK4CVMJ% z(c*A8Dx6nIsxE)@%jKAXzwJ@wa7J_babn}clg#HP#>es^k}b`{Q(|UECYf7WaIMTN z?98|pp~x?mW|p?*Nh#rxF^OE!�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 literal 48315 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 B_NM>< literal 48765 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 PpH(g_)>Ggwuvq^AV&!^A diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest/testDoNotBreakLazyLoading.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest/testDoNotBreakLazyLoading.zip index 43023d502a1b5cceb763c0234093100c80e25980..54bfc3b4da757689d119eb8403e8d763e84a816a 100644 GIT binary patch literal 38576 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 literal 47276 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 Y5Z+R3&!N6{Q~$hk;&2X9;y9fD0Yw1gb^rhX literal 47297 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 literal 47297 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 Y5Z+R3&!N6{Q~$hk;&2X9;y9fD0Yw1gb^rhX literal 47297 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 literal 47297 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 Y0$aA=9X5er8u&942=`Xz*Ukw32gN~3xBvhE literal 21249 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 NG&r&p;@@)8`7PIU10xeV3j1YfCv7$U!^Agc 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 literal 31969 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 WxxguF6v`j?&jzTz-vi`OsQ&=b>|&Jw literal 33097 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 LO|pFw`M3WAS?tSz literal 54979 zcmeHQ2UHc;7JVpKLD7f}P+~=qt_BM#AV!)BM6oMK5k*h|3$er!@--H$L5)$9SfY|B zA%1J@T~rbiqxonw_MnE?Ma`di!@QY$-+gn-4DYknk6HN0TCR8Y*{9rd&pmUePe?_} zIy#-Mitbrz)qwvve4%sY{_pduI$em)K{qjF{OHuN(Ieu#+zr3Fj~$;fDsDuYr+f6I z#8mxXp6*G}F>y)msY%fjxPO|O9uu25-qY|IpO_Tq)%U%sx{99HEF%Vg=n#=Usk+X> z^09?Zr~m6w&-{}oqnyvVp9%`Mv{-0yE7c~iVh_i*_tu72p5JlgT1Su4-!AwK*7Y$U z{$+gCfR&f;>}$m#&ab4?1*=9Jlb)Cqo9fO3_S6Heca;^e(_+UXRx+?E==GwZcW!y0 z*92lDy=;Irq}Q8<-u@qz1Mf9~7)dW1V3=Mw)B;q8nmJ-j8L9o zi39)|y=)?%!srSpC8M*U6jmDh#;iMAYucmVGuzeg<2X8A~uvHbW#M70#Yf6*pR|} zwp?c&U~PZt+dsHU{~@<)=*GNUjz~$4PfT!|G$u)3-=At$6}2ImAMV@xu!n77iOW{E z6)O)M`|ZoxIlm0oZ9cnTYS`Ax38x#c@7nnIqNaY8etFg9!QCq>9y}bl$lk}@X2(w> zUiYchEqV5lbveD(xbN9G>gt$H@dr`HR;k;k*?!BbL$d$sw#u&S ziX88{gL`f}`Acfp&X_Cz{?)Tu%C=siuj?**>9aREp=QGK9<80fZ}GIjWBZ+3FrZUp-isIGuJYTdY81}XJ-3xLiaJK`(8>0AA*1XAavTqA4Cla~ zqEi4`-~k0*&vl4!``BpTp@{0wNA8RAv#6ezsrc8VTaI0f&)TG!n$yP5$li%=^Au;$x$X~3)iw%oaZ zae$R$R!xD`npHT>Qk&lxs3&x6g;-4q&e`Cdx9XrW1+*+O0L-cvCa+3IlxAF^yoo`X zdl|yfC7tY+Bf2C|Wk;9LAE}sluUpOE>yO}0nsxjSb+NW0hS}V*j6fimnzenwArIT` zB~t=-zZZM0p>y4)b;i}MT|2PnRIlO+wHD0Z>v{dr_JEnrz0w{{m{9c7Z}$rBJ?^!@ ze)RH7ZPvuMT5);vu}?o4kp6sio7`nR|GZ*Fg(h#w_+Vn~E?-o+I?ez2&T8{h7T!2g^U&Js=WD%RI48ID z+^_*ntQ}l$t}Yt3@|^7z+tn|dI7YU7+31j8#U6hIr~P{ATc4o(*&Z=@F;RtAs>}{= z?%trk(ON>7a& z?-ZS!l011#N_uKFf4)hUn4I90nCxU2u&CA}F*z}HWL#`Vr^vnm0fCW``W~4^PAJdE z3{EJZP|cnkg<04WW?W8lR$n|JaRhVl$Z>B7{Jolrczn0v}56S#!%ez~C?9?H7>wx%gr>tBbJ8DbA z)S>Y|U7MJDqF&K4qEy7);-%!g;(A^>FCcla{7Mx$UkF4`osN2+xi@Du<&`x z^^^$DT{-tGt^_@w*JMgb)oZ`EZu`CO;uJr9%*l6{+ zTTf>1I5VigvB8$BACzQ7)LA-iq3?ob=Rf$pU-pR$ON&0=^tHtqoBDlhGOCY#;DQ`E$$E%7PW5Nz-1?vKJz=IKMS#pUucs;k&cP zCcVAxWYfwHM?btUWvbomq@n%RCO`gY{FMr$-}|WLHz3g7R)8^}|F)u7v?=L#iuls=Qbw_1dH@}m53sKO#e;9#MZf*wARC{r+?O}-?$dtLyOU~We>*&4+O6lu zAJ1M~(D;#+v`lnPu@Bh&(l_OOuD%N4jM@TgP(Gpz=XTwfIz;e4(6H#3-XS$+J6RV# zb8G6C;xYPn$8H5}zsl~@)8~z)m7UkB?=Lv7W z7e+3rdB1VTy%lCIZU1=gcZae*Y%Hl(i7O;5mqg9{g;Q-Zry9;zz1$&RwZ4h0wd1nF zdLMDJ&E(33Sa;t`_wp;oy>)TYkFy#Vhej8DUgv~$(yJFW#$2wyuXx&@*0VZKJ2!N& z?&MLAymt!IU7WH<4$01ZdjH9_dpmqL_h>P1&G6h&v$HP8x<&47QoeCq1-`spWseh*) zAKl)Ruxz`>gvir}9qty)D(vxKcV>gaw#7f#|9xmr;D53`vu9R$`>NgTi3f)5>32LM z=4^)NvVu+>A7%ty4d0kIF!$>I?Jq2(!uuS@T-_=y8j7dPxOC#>j!Gw)=t{e->@*qf zTmYxZo|t)NaW5%;@{TDb*QRAQW9usq5mJ!I;(-k#uKfd?xghW}3`vIfEbUn$jVDv8Kg%Y>n1PuiKeeM_&5YKhz-35L<;<93 zB@ger*u0En){nx|KyX@z034e@XO%T!o5Q@C0WFKzg$p1Jz?#oDH3M7jd=<6sl}leW z1+-lHsxjDd?5n20YVE7=7$oF zr{Cb=XiplMe10+XRrq;mgfLCUiNSej75-<`F!{&-q#g>~lBMuJbUTH>|9<6$^Bw)Z z+}MTl_rcr`h5ree*x-LT+WFt2TJ!V+`8#F9z)wD~4%odb#)3cNJIb}@D3YEx+@*6X zs)7oY`QiJL4?EdjDXG)%=@IvCzIg+dtP8)<;PBBN2P^NMwPE3~1BU`SH?zO`aGXV zqvo6rpMLS(Cl7!8+SQ_Y@$r+ps@I832pmw5d2_hm#mO#buMc0ndwSrA^sW|-3M+Q7 zJ+Z4#rQ;1V?*6)b$m>ph?W5d+d%v@w+u(n{v9fdcDa>(mPs{qj8-DKc<4yk;OEZ?Q zT{x><=bW9Je1jg=3(o7k=4nk$oXQ*7qa$#tC;e;!O5SoC*_yMJ3!PJW>&Kl8PPO1M zGJ}Q~p5&08_6X*m^k{WU|IkMT&)31JOCmm&I}p4Z0mfpGtESj%DZ>pfT+HLWS_CD2 z@@s&$r5nLS0)j5X{u?!xjh;wAtX5QGF|;W3b_B*^5D5PN#$sq`ln-_w2sGPR3<+*| zNzUMe1YhjK$y<4za1`DL$xTjy3>p;gCR;-NGSw z9lXv0gBJ*|Gc`qoa4!u8o$1hMyRf490j7wM{Ft%+Af?BAT^KqA6CD`hQ;gnFY?dwv9s1+V*X^(&0jl(n|o`f-04KndiK{ znRnN3>d)V@rvIV=TdOzOc|iV*vf{)L!Y_>)VEn`oVyXK-pBO?ihe{p%#1Mi$VPZ(g zQJdoJ12_jW`~l9ORNa86e>%W{n;Jq~%q4YTVEGgm0+_ggv9usy6HlQ&bRU6OIf|bK z`G^Y%G*RD#d{})d@f7Mq&$o+ei=PJdql_;P)I@y~@?rIvy_b9Y-0h2vcL8PZQobzD*2b#Q=yf}=zImWO|a=%c>gS=QT&w{%#rjhXlN0PjO z?D8OU>gCy^Z>W*v!7Fi)yyiskso2vNmjUsU&4YVt0YQ~BQzMY~R7K@gA)qz`3W11( z%nWd3xns-#j8F)-V(SI*;S{A5QWv2RrVu2ClwMFeCuCw72@+$;Ac(4<^21O^6hvfJ zgX32N(WI$ZwP<6X{U3_>}h2JU$!VveLp_oKoQEu63z-zz!<)tD(-PsFa!$O*ZXmgs><_NBdn42 z-y6g|o*HBPh^pz01nzrfR&7n=^meB38q{w^^L5q1uVecXAeSNfv_K6YrcLqFAQI8D zHBB$YAf%KA;Bcjq2y96ZN*eqSHSHuSD}J&m4eZNUA()p0`4S>3FMgVd1QY~SBv1^* zO1{UYtcN^25f%p`OO;X-k_?{CrV|By;@TlgmWnaEo|`h2CwB^^yv5NRy;4seA%{#& z=ObX>i7=FbGo|dn#-|3NN%@5ikx z6~hm951;}?5+yDLs!|uQB*qS1ZTsGg!YE@v%E62+Q6WH>~+TM<+ zeX~V{Miqr2UHG}25M6zJsmVQfrpueb|7y6`6WNQRe21!)@D5d@gINg>Jct?$0LoPj zs5H_`r&c*U{3}uw@F){BjN^%rAn}w-`6aVz397~2OQjBwwgi1ojz>J5D_erbRwO3K z1Rz?1V2=&}JlfHc7>|h|Ic8S|fgIKZ2se98@5257BV(*s8PV1QTEg( zrUSyDrBR%?IAY7@3`T*Ak6u8uuERhvv`LiCM8tj;Zzrb3E)2lb&rX>hB22XF9$b-t zkSf)sgd}gdiuBMzQnuUu-xc+lr+g-!Xw8*v@pZ`fLQ8qxko9;h`flH z7iBC5)nidn<%7H=H&D%sfJFlv)oVzJ#W<`q7}ScrIm(+y~&G4`r?F}#2dzZp~Z z-MS7MVPRSsyny_27=uL`+?QB*wwT@}Q6KK~jwg<{e8^=)!28`WUZ!xV0<;&AXUb3@_~ zI5B>MmmJ3fCl#FNFD~K`@NYv?K%i`u4R2E-kmqR%tB|nKriltHST=+muJN16MGtV&srNpk0&t$e#)({kk@fmb0%oXsN`p(J%J&mu& z7ZCb_hT);I-u(-|6Rh?h3?36V~yjc-Dc%W~!J z0ae~aL7MURq97BRU^?UX4aub?w82S3^*{K#M35o{GU1d4b}P@zMat(E#*R-J6*nRc zm=hFh9r2TRcL>L%FW|B1t}?YrF{n*^U>nHJO&J2wW?3~YV9({07MQf9DZ`zTCV3qs z(j$H{dk;vHyN3ptXla5Sx;@~~S22)~LB+h@fU+lfD$`+7HfHHT7i8@Kz3sdxWUHkd z6rDpZ+7QbcF&^kmthKn_RLg+&8@nd+mO7tQ>o zbq9^G5cvyyfDASrf5cz`Rx+pzryM5m0hTeBPRb+zf>9MYW-|rP4|oF7*U(7k!@;oA z!Hf(jvmM!)SZVMwNN)3}itR1F6oMJpHhxuze9P6CdxMB!gQvXr5Q5CWHvi%fg>9Gd zi$COIPmqfRUjxFi&A$c&DHz=y0DW86jaXmAdo=Kk0^@gR$kk4xkq-Da|3(d@(&)Mr zJT|H7hf`WCM`(*uxDo&}*k{CYMftqWm?cH9vU0!L$6r}t#nOzTUoDWYe2VbB8Z3Hy zXmg5S)m;TA*uFW5Rrb*$kQYD{RuQl$pQ!`{QnDe(f@MSS3*}RU5;X`wzo0xt0F#6N zyErDq;M6ubTqKq&$|pz;=xhk~+{g7)R#@|6lfS71V$vU4L-5#SQ4mf;wWb6aZ4``? zCzw!0nGOovMkSD_7Kit4pujF6${LD|4HZ)tpujU!0x>=#Bt-ZOkd&`@O!%i!4L zI94R-u0{w7QPGl(<1z>1xT{dSj5?P0n1F)SW2@Y3lxwRiwI&`pt*B# zjT1jvuzn@1T6B@bv_MnWA|2wVdRjhEjYS15;@P9%xPOyFfgT-ELx*_wC}5cQ z9rWW-Xp<34ytn90L@XdJ`ZojOV95gca5J%6Oqv5@fgOPpm%_ z4SL!91@a23x$*V!a@n7f%Z6M~FPpziUO_fo)dZEco&~+F2Po^U*ftV#viQjo2|WQg z3$=iwA}ByKwFXj>Bk!1qq^Ljxnrev_Xhc*brh=o@9WYhhLCWL+M<(J$^jx;agsJg0 z^zu-dPA*goQ@y7ArSu9hqAc_dxll1aNrb|I=?Bmo&b{N@a7uyLZV&|~iItUMoKX*h zY-v!2@$L{xHjE=t3mAvg!{BfB!PhLt*V)UXz;~!J8$jsk#qpQhEBL?h)%J36Ystlx zlFVOpuOQC&ntQppio=Mt<8J`u$mB1*R}crgme>UnR={|yI5B6c$mDK7Z08e;6h)Kx z%qF9I0p+Z=8;)aD=sX$jAd}w`$Z^bHjL*#R28?j2m#7)XHqpxZN+PK^hHlmC0N6Dh zE3;HR)OZw;i511)p%pJrk}Tqz0@@FXQD(d}E3pV_0SMZO6{Nh~UN8prF;jy4v z6S1NMwb&LiFzH>y%7U_idaHGbRc2BONETV3)jq?@qOh9r)%^0j`WhpubiL;<>ZeGb zjQ}U?8;7Hgg)%!pMvf^NEMHw6`07{SSF?N}m}mXsWqc@4@JJ_{YI1@&P$N_fc`V{7 z91gBmz-?fQ1ZCxkHU?_Q0QbmWX#qzwa$H7Ik|SRNMN-617Doli`C1D&D##JX3XB^#*J!{UJ;jPKOLU}K{d z5cD2nl-U4s4U5*GxFzJ`w9xJ;xwz661?3qPSgj98#*ryTlZx~SwkQq|ixfo@8BwuC z;hcg~6WWxhYf*qT@%7U^1i+g}fdZsEf zX$V3VQ6Q69SW#*m1Z*GtiIGKiBmq}Hpp2erIOUuacH S$Nf3R{WqEGwzf^@|L?yB*&-qU diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceForProject.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceForProject.zip index 770709b746a433f4ea867976311766a86a4086d6..e93e4bf15f0c5ccf221bc96816e14e231e31ba92 100644 GIT binary patch literal 11904 zcmeHMYfKbZ6rP1eK^{ePt5%?xR!X7lGN3gDH4!4=WrgKsjJ3QLT*ViUy0xwG6`H0r zHLWISY>F7GeI%)e*&3sX4CqbHMJW`%T27Iupof(&B^$tocq*U z0vV0=rZ2B-!Nn)Rzq<#mZN?B?IktMWmya-Vpr-E}5QU246# zy5i;fwPmInfsN(OGmS26u#-IVF`Eih#(~sQT&1_Ht+u%mbWLj{@M+q$Wa;Us z(1zO&bQOjLmqx6igp%YcEefF}CHmpdItK^sijObe&0P zpEp<^7uB@tm8OP2f4Mt6(y`#P^ytQqOWIcN+;zD^pMTOnuwvlQNX(^&MROncWZc^o zwX7jI>h6IB+eRObAMH&FE2%uz($(8(Su!WQ?~E}hB4sdt?C)!TSeB)vzkTCK)t=Ub z*YbP54ZnGA$6)%eUpLGcoHO>r%!i%F7hh>&o3{JU8q(d^bn4aPMc;2O>)XukIhT@r zdvoSc-r@G;Z9^wp$2B5zzwdu4trq! zpRV(})A-Z;BU=je`$9&OOFJ0b5tB87?r3d&S%taATlt{ZrNh3WvPq=!?E-_B44vP~U+RXeK~Y)Lx}jhmFK2?30t!fJ zH)IX}cSF7aucK}_p4@RN7YSiEpc}FV?)-#qIG|!TYuFFT+_=GO10s+jslf&%Df4&<9d+M*s68kVogoZLN$%I*|Nh$G zz(I*YiO3vxe!`&i))zC4+{a~o<<;6i`JhDfSH(d|(mpPZgyIC`wd@--)gy6G^3Egi zNT%0GesmLauUVnWlXDLn zlqC64aZm!`sC^z9pGaRa2Z79Vd%1)%4;FD>g+YfaIY0ir#YLWTvppNsVFnlD1_j$* znU2Iv@AhQc=^X~JO817a- zD6MwEMBH-E55#jMR|F0ihTbowbH;IwfC$NlsmBhp84TzEmeyoGNLN;qFjoC1LW6W* z0@x)7iz{{u1sL9NJS+BJR1DP>yWC%zPhrImIXc(1Ca&0>P$)opLKJ%`dIOZI2mHZ+ zuGsEtb!WwX2PKg-8W)zJ*xZtxSn1?k#1;FcKpGaG{M`0PO0mfWhpWn7FczTDATkyg z1Pu<5ClEG|0RiC^E=))03*P@`1jB+;RCaj(+bS0lKr1A1bRp1CRZ5)0vH;Qj43&n* zk&v7?c>kOG1T;cNFY=}w@&5ObY)k;VfT4P?Zlppg7@F~3eG3W&77OXyl_iYEro7vg`)1d< zSGP@}p>bgey_&G&m0BX;y}Ar(rH~vF`x9D8K_s^mj0F${9?*59!-sul`Op WCWT!;bm3+g7X3~_bx<;c`|lr0ISifv literal 11904 zcmeHNdrZ|;96y(bfFR)mUx49OND}vYFJv1&Hf1t-DO{hKmLeCuhN3)_*kV%~tv|K(WBU)-P%1F(zNp{ZfUVguG&hOlF&hK(>{}k+}mp}M^ zzR%D1@gpxgFlZD2AQW6H4NKpBPO4Q(vo$K z)#X-8Sw%siv(#!SsBjh+mRX9N#SZJDg<&9YOlOdN*uEHhMP)cJ1>H9Rp!{=hZfkS% zlEik)h0OdQ(>tcyWy6{RGvZRa8}dVTrmby=o6;S>EADJC$WxViSQeIkGxj5p43*j& z20)6mQUl5%t!#=`)-G?ga_M(v)^bcU+Fg@{nlasUw80l{qLoP!DucU63tEFuw4sA$ zOdEd$%Ug|XN>cknBX1+-(nyP#Z^~@Q=CJgjcb9Ct2FvVKSgwh}{8?SHp~$($T)Dnj zsjY}xLG~1V#XD+q=bw#_s=3=AU1*tcy}LEgG4g8V_uHTB%~{p6chvca;zxav>u-!b z*<1Zb#P;dc?Jq3{&F7{xJ>OB06koq~MSaa*zdh*cJ~rb(M#7FgE03&uz4k_-dBLgB z@WM;`x)ZNIUi@5tz}$zm@k?vc;vY25*xK{B?`TWPh?PZO?rm;4Q<<9@+jh<#5jU-4 zLGRzU?pH3Imhr}&{cGwDPuaZS;@7diUf$l3@%vXb<2q7%zl(W%=J=eO_15}rp%Xi! z?`%2!^6|yrRu!~WS?exOOS@Z@*_r=o)3PI-rw;d-5J3%vz5<{fdTw-R!uSCA89m8D z&uws2md{3vIj>@UfumG$U(IbMHKh*Kn6UBS`1HQCW2f^V$OZT$2!Rmu_ds0Cbza^_9nIFW+nfW6>#|N#`k8< zeShMTO-_4O(eNEpw_Q#=5;Y;GEo#xE-LY397n*lR_N1*cn>hSPv=gi0cCySb%tW*k zu2MK(YJA|GRx<5GF*_4Z-k;FZHxr1c`a3?X`VTUqgYWJ5ar*vh_tO@cpn*bpxnacgT24PzE=BLgr4|I6XDQ06=>#KFx# z=Zr=pW{8(6o%&9H$hTQk_i*KZ2A4uL)bPUup?eg$JK-YOs9y%P@KzikZMYezP)~YYNKEm@)Tg6P5CKO%R;b)C7~mLit!MV7H$ZXvrxU8h+V2*hVW#4Bm~4)BZ!7xOfWOl(*l8`O$`>Ar&}i= zBs%6ZAzdt>Kjh<(dxVhMVga!jC;hx^t@7!Dun`3@AHL;P^Al%9!5dz25a~1}8Rutd zT*LLjH@G^4Z?M)DjWQ44;E|!SxPvyBq}W3OVEQaBjx6n9k`L10D|)$%lIC>Uvn1eo zLx4V@*kzD6WGwU<#r7Bilj;7Kfr18iQhD3<)@S>11ke@Skh5)5< zMt>B>IepSFzJ*rhuMAwTYGDPU6EUZM@Ehb+A(k&2bmyQZ zfTk$EfsBJ9gcM8w`eP!VEpfv|ki-OlPK(TJ@pKP#VF3^Y`e%KEW6A6s%214s4hA62 z?xDj4nLGkBj|(|a_A;3I{Tes3PKc=4sn{M(Ak4cjgfe25{w#r;wQ!`I zE78^r?Gl7de@n!%nuJ&i2D&VAQbT`N#4#e^fUNdbJT(;2%nKtLbzNbhMTZk%d65(? zBarreG9j=57br73%Y=Z2Br7K*8gma9axf`Inpq;i)J@ETH}eN+NF!$Q31a4Gk!yWM z5FZMmjF?4d3`s`)l2~#C!FS<`F?<)QW22HGgW}i|LMS6H)ZaF7PKt#;sGP(sI>jDz z>E!U9{?3VGlnXH2;XzkV4hDUsj3)T1#S@02KJ)siaVssFQcCmnniinXSHGpCR6c!Xg1fudqjff^HDxw(FSg;a> z#Dc^cjU5#gdsHMQ!9q|&Y#+A#XBcL8-|X9&_hx4I%l{*xS>Q+ z_gjF*hnRy8Q9O_5Bafngy~KO;kG?x&Glvj(Q`mX8d-y7}~m#Ko}|nRjNre){rT(>?O-zcdb?v}By^;*|9# z^Cx#2U0$%_&!V-3*_j^)90>Jle@go0!PlExP4W-3EqPSr)FNb!;m7;izWBbnan;H7keT;;(0VUe4NliW0+F@$k2(C zPUA8F8I{Jk8GyUtaYv*1&ps^LeQ0r7nMc9d05g5lWcfFfuSMSU-n(c}#ixEXHuwIl ztnBmn#Hr0?CF`ti-neizsjqiSSx(44mrGZt9c_Q{%6yBT%Wj4*bkE*caNF_RZj+Rn zMTI5pb`F;xc;S2AZ%#?%#zk(kfAv2TIZ}3DNtI-v-+zlczPpq0N2+ zwXM^ugXW&AAMV^V_>qhEIoF?#^tSHwnN9cWp8dClrnqFxOUt~H^Qd^AJSlrk)B8&T z7meEI+H!XK<%h5IMW6sO2fF;#RXz=bNm*xkQvfB9_~8mKNyroc6iwTi6`2CiVsU3w zc)CKS07@X;PyjW&zZC^gO82*Q)V~=8P+Ck!6hIwNTT9i5*e~m^2ur_3)S;QgPSlQ* zrA$anh>26~%Z)0bTZ!nb5&kD_%oaR*Z$8n%?Wd~JhS4o=&bT_SLyd1_^`=&5jpE_TX>95c}?;8w%on7x*!V-CXVRiBrb%C#u^Qs8kUKGBk;^^*LJQP^v_#b6yA!E?6|me)`)`J^79?G4(f1bc_;Tqx84nW z`uN`Jr_aKdTRJ-!7hj+7KA`#Fgp8AUg?<|x4sD-QF(p6d$C9^8Ef1f~yJI%wJISji ztphqA)vp+v`{&@b=7UxjI<+1%d{@b>7&plNH5ZnLs>eH4}y7vvq&{Oe)n2G28p9*{r#6Z=t%c6j-`sisXkwX!c~ z7lMaL3ibk!-3;eC^iBrRV zYhrRGe@0mD|oa?ep^3o0YrZ_ey- z@t25o2j_TBNFAitzPzD}+1UdDjn1@7dwgfr*!Qj>mSOhZ{{5B?9`pSN19PkEBdm7} z*SGNAc4Oex$|1EY(^hRmSBbIz`O?SAge?}y^XpIDuCxuEcfaqQZ_gSk`VKguiV)Y$6O{A-`hGS7$~ z7rHUw#TV1=HJIFTe$(H!4f_36>H5++1+R8&YTot8m|uqdxwBvH{^HuL;WZJx>^7wB zd6MgASoLOT&3@x=E23)k*Bz}s89H>-?$(nQ7RZ^54ZhSg_ApT5%4yZF)Q z+85Jn<9i10am~!$km&0*+hRePeMVG`>ml`0tq)8QEnWo*O8=EF;{~<3VLmiJb7T z*TfIkNdt9yrl^i#v$%G%iruT)wzk3U#d#|S4qr|0W;6Sym)Y$xYwvr}EW~z=)ism) zO|89Gqqkd%>~?o{8uXpTlARkyE+183*m3_ceU>uHtp>GA;9EPnTJ%!IWPq*;CZ0sv zu9B$sN9`suC-k^G+Vn0^P*;KLz=~dGEp>w7ybX1wbvK5GCy};&kL$onxoEVH@aq(C z_g3lW)BhJg7r@&ChN?Xb?i2@q2yjC}=AalpM4pTmxv0d)oq^zm4wyki0|GNF#E-ObLjqkiW$EK58rBU76tPf~2{W4m?HM#6 z#Oz490&^q=xFLasM|y;KW*5m(nbeG*H&B;)Fs|~T8BSb_!K)oGDuN~!O``abHQ z9-#O+1#S~$2Ed(9DFEIKK+_EgZ88Axh6E%a#AW~*Z%D9t$GfA|dvsO3~@rDFM zW6d`tAiNLxh6EHy{2LM|Fyv^uXg4IFfP&H$a6^La@#3Z_xDx_5B%s2Gbwfh)!*Om% zFnelT%pDjJj*pCrj^}w4!_~Zl042vqej1J1cVNyld4k7L%9Et}qaV$9u%jDtu5^t0 z%dOb%fdIqdT#H9pwq9XD(J_R#-u19x)IgL**vcwf##B*ZPMi+rEhK}Al9N3U5&yj| zLi9_3p>iw-Bwau;ZA0E2ftXkacSraufJ%AbIh}v%pm7C7us84EV8Cl5l9_K4@enL5 zDW$S?2Jtk6e1mc*A&#U6J1 z1dt@+L_s$si3ZXYNn+q>B1wz1Mv@o;2uiUSBnb`+rdEj32uVws3IvlRhL8}F1QGEc zNs@e`EIkUXk8KYm2+}z`lEg4F=>iIp^nQ_5ko{t{Q6*7GQs9)i3oY{=^+~VNV;Mfi zAWIBIsDi%hV8~323cY#qBGK~0T(P3{9;LD0>C1v zk^u0NR2lW~awc>gbwGNd*3lj5Wrx>BW)?ttH3<9v#pju%S35qBL3%aVQ)i@?17BO~ z%6jh~+UZ5)0RP_m|KHsEA0W5%IQYgb@jpb@!H0O618`v*x}cU)y(bPjsC8tM%Zr-rwW~40ryZZ(uH4`@_xGUXcT<7maQ+J>9${^KAQq zg&!=lR&}es?R`JZIpnXGl{xg(V)VG$+B=6nHKPo1$$dEIjzMja)1WPEao_UWK<=iVFQI9BlfNbrQ+iZ zK4^VvBaq3@6tWnZIo1y%M;TzNTVHYsWb!M7P-J+H1Pxt_i;NaM%(i}CV0EL24=*D6 z6kV&3(gd~0OjEl8i+qJQHiE@byliS?Y~@ArGQ%dkkO|U^?`8df1>b~^OfNip)rK2< z0I=dMi7$|1dK(RnV0d_tfu*S!RRVGxf-Q?tVCKSDMb@gCh7YJYRyPDcTrYU4%plj~cKvy~9NoqclaEV5+OK z)n&2OyakuOw0i8eg{O~R09J5IR4f79QU)-M zgSe2qreO^d&#HGitIH^5)A_0#{%RPrS`yLCYqyaNNdXOK=9yn0<3xy8xz60 zaL)yMK}oIIl|`>};00sVxG&+v5TO?Y2BfSFms(V+QTa3*TScWTss3R$N=u1^>;SID zg;c$SOo9`)&@hr6*!yZmNWvDCf|x^hz*XZ=p%4-d+(SD7;rNOZum1iq_X09I1>FFk z;I>>gtOKI&B6GtrFYG!4b}Yt$g9QkAV;93=906s!x5H3YK+)<0=)95#DuNqP8J2kk z7tF9dEin{k@DTD2F4WQ#u=-cbsJuXR`ZBCAfJtSk(_q5A$a|?!Sa{e-fdzK9#(+gD zWN=v8tEnuwnGdW0|8fKT%e*}grR&j={fs#_ME4u1<=)3f1QMG#!6w!mv$YFi2X)|~ zK7!uxg?9n`?RP%dXnqGLPy>OLA7{fubs8SQ{BRS11*G9e$TFZc-`ERC3=W*=1>`mk zx_|%&3&_xp7$(LIZ1w_j7Y7=zfT({~OSORX?u?-`>B@=%LVje6cL6EKfu$me%d6pm z4Cb)mT`;tzVG#nD!e(wYLF`Jt*t~X~VDgyV6U1mu-^Kx=M61VrxzDJFD?KY)!HeS0+J1T`$cPU&P^NCdN@I1ceTXO4it z;GgjF1v*YP79cOj0XwBOj;I>an(_%pa3B9AHYP$?!gG!xu)*mlRZ*6U>A)WdPWZ{e z2P$$WQgvsxvcRrxv8G2WM&Z~OLMguH2|p7VU=OAE3Je%+AiwQ`k@mqZ=X6d;Rjz;u z1&&eNK!rj}itJ+){hYW=S+AGq6Mj3i_D0sUPGxZ>{66o4j4FgTfCt=< z@j($X6}%3B$QgaH)kP?I%ABBD-N7*m%YK;1Xwkz=cJ!`|+Dv5NgCeB~xT(Q0iWj`G z5iCv#z-%{yYn|WV($SBQ>`QJOSQ_yrF@)>OpOG|vqgRlL$vjSq_8yYPGormHUoVylag zDB)29mZtWDFpRKr zJz&l^(vx6RQ%L5^*9-!}Xb519Z-k0~5MET}VGgbg2ITM?!PgWFvc_>d%p8LR2ekJ3 z@s)x!gJPrwb0(6OfpUrzf4(xH@c?+Tqho}Up<1vE0vyyEaE!?TLd{Vx3bLazdzl`9 zJQjgM8xtibLjV*dL4-4UI1_8+utmYSmih!IX*{gYSC|^_H zRde;vNT?2b-3sF?1!)FFH77qRfiVpLR`a}(d}W}LB3Dv?Cq=MQv>hc>283it3Bv55 zfP$P5MG#&k3tW}BaA6ifZ%3#eLxUXazF-*yqz#Z`MT{0|4skh_@fe}88a*CEN0B+!dEVHfb1dHo zzGe`REJ2QSLZ}F&*K?!R&BTxN(%1f&g+V}-;BHHWwytASjo zJR&)4fhdCTa#)aK1;q-rh@&#R+W&+TxdY`fV_>K z?H$J8#UjUeE-WEc0vsa9LdHT~Hs+2S1nf8kRXGxnR}g{L+=U3pFS~=M>t+dP%87VQ zYdS6@f?44$9B>_t5>ZtZ$#K?W0rGMjaNMQmR8$RxWLa?BWhFKyhjk4ak^P?2#D5Ek LO|pFw`M3WAS?tSz literal 54979 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 S$Nf3R{WqEGwzf^@|L?yB*&-qU diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest/testExecute.zip b/src/test/resources/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest/testExecute.zip index f78f5949d69b4100ea3efe0494af1372957f6d38..cbf3180150009f59c60ca9e5cc9c728743dc5fc5 100644 GIT binary patch literal 19211 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 Y0$aA=9X5er8u&942=`Xz*Ukw32gN~3xBvhE literal 21249 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 NG&r&p;@@YlmXb(Gijqnyg{WjH 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 XNNX-|f*XO@2mDh6RNwn`(0}?509IoX literal 33337 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 diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest/testNotToBreakLazyLoading.zip b/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest/testNotToBreakLazyLoading.zip index e9a35ad0c9ca91fe1cfda9aaab27ebfbba9be6ab..0ff874d3d782dc86e34a7245f11fa93f6ca82098 100644 GIT binary patch literal 38558 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 L4rc=;j>Gv6^LLNP literal 46785 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 diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testAllInfoLoaded.zip b/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testAllInfoLoaded.zip index b54c452f9a0c918f987fb86845790e97b78fe4df..38a9c2405e32d20393bb7bb5b0b4f3150115689e 100644 GIT binary patch literal 38558 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 L!`VQI<8b~1;D(TA literal 47073 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 GvHlMyWSB7k diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testFirstLoad.zip b/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testFirstLoad.zip index c067395b9bb586f863a0b46a72d4dbe1332132db..ef97869f4389262c10254200b20a108fee19083f 100644 GIT binary patch literal 41664 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 literal 50227 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 diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testLoadingAllBuildInformationFromPreviousVersion.zip b/src/test/resources/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest/testLoadingAllBuildInformationFromPreviousVersion.zip index 139412e06e141dffe029c6fcfd57a475ec9d5795..c61be404819c31c0c7087b19a3b9bc03e82b669c 100644 GIT binary patch literal 38866 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 bX;5(Eloea@puhG*e>aEj(`G^c1CRHAiANTu diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testDoNotCalculateExcludedJobs.zip b/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testDoNotCalculateExcludedJobs.zip index 43a536bad74c5fda1f7fd67fbf5728342f0483b8..ab00630bfeee629462b14d2d99bedfbf0e53ac54 100644 GIT binary patch literal 10411 zcmeI1eN0XFef4|Bx87PZ+q!!Z@b&}T+zf! z`jwEJU!U`y=Y8&5g`6)~2gplamRMwe<9JE{vA{$aO_>^l)@;z2h!^z6YL!t_NvP}U ztBtQ|w1l*-UQu6HMQBZ8Rbd$5=gPj*k`J>b9Pk8p_yE|S6kgXz^=pm8&UGaLF1I(( z<>-|ITv!(T!undR!K@>6eh?Hq$gd26yGcIO7zt_#i)p`EZ_vGDt|=$#>8(G|xlQS| z^^$eoH$M*}QaOoZe55v;p%S5ByecfSW8&AdPr*;tH2@Ui2dU5-2#H;o$EF0z$WtD| z%*(6;1M2uu@nBZIfcGBnwlT7gFO5sFb>^>qH|=0&T(V7cH147hkor;BYih$X1s|xJ z#v%3_JOGp!v9)!z75d5~OO3$}9dS#bWY|rjEjRC?D7xj|QjAWVal>Zi6PvDEt~Nh0 zm!p~O-h4U2@L(~jW@5|PxyIikn)fu0zET1PE+zLpH)-A_YCl-o-tyPog=t%V#%I!< ztsj^5R=w3Wp-U<_7aFd+a>^EeW4S1GDMWU^O;p^HCR*sqI5NAu_|@<;8_O!b=^hxq zV98C19l4~8h)bU=n0t8ZPfKyS^zE6`mB)ILUoRN?KK9O7^Q82*Z(AOpOqu&}+wz4o zFWzjIv^RzBn2MP>eE!ulML#r@k2FY*jismEYsi|)|FrKw@6@@TMc#_Wf1KEwsnUPB zKMQL734ACpYE0Hdj^1dpD?9_wN|a|=$VW!yLpj$!zige(9vaSC7ZI zMsvANUmvI)mf^oOqfKWqVI9mZ2!u{&7%$u<%K_V>F?l1sU9N?4OyX_S# znP&6^7TlDjUE5dUVrK3h%oY2J2?wh=b4n`aKyzp5*k$*Tsi?N#UInEb65+1~W>qod zCBm}Wd5I?Y_v9rSDJYx7keA#+P9iJ z(HfIALFc6_81qu=vrS|1z0uoqMxs?ucEnzba>S-29=EZH{$`ZH?`Co$)eG`nfOilNzqB&cqHAvAjfLc2n+0ggE?;jc)E_`iFaD0Z$-6Nb?2 zQ8KF@n!OU?t_EJnc0O}#P5@hA4<@f@u(XeS^=E)9qz1Td6Fi07`+BL!dOE+>qerTw z5&FOMUS#R3fi6u`1Oy>NAadYLj=kRW$`UdCR_rq5WhV(b;-z*UVt~FQBN%BsZeZBK zK@R%LL!{Ecku)x;=;q}MiaCuGI-n@UZ1|xZ4GfZzV_?RUMUi>Vc3tgmh|hC2Uo4yafd7n`P}ipDP(i^^xSmysKAqXl*giRQD9IG_r` z#?X8gzY)J=4mcK@%H}A{a6pLZD4g7cUpyA7F&_mqpS=vF#T74{xy<<*h`pit>@J6N WkJwuwydeQV1pj`4h1C;7e)=2L*RHq# literal 10411 zcmeI1drVtZ9LG;-yTO3U9_Svhb^lD<9Hj`Fz)%OX;W^5qD_KA(^ujs{Y<)oG58^=a z577~I2GK-7(Pe5f2$JYBStg6)Q69Qvj0_QVpoBSb!-Zss=iYJ;y}bq3d(Xuz5ptpM zN6+W?{XNb(->Q?ul1%^rZ!m1~iE9}7_55S-FZ&t*vOy5A5N1o9&X{jC>MXlaj9OugKh~&!tY^N9m zNP(f`fldJnf3;Jf5ul7#qx^;9UX8NP#HhL3i6d(fV&dSJJe-=8t0B2i?6{}A>x9I> z%^EQeNPD{FUX5D8(4L6hZF~A-Y0rs|w#LmxbzD%x13?db)EK7vxPbX48rq^ zn~9RtKakX$eD%}I_VL8tzJ%HC$3w?^l0FYPzT4iHFtf*=lDPM$M6cG@n%;go{@tD0 z!rGr2weFGEAIYh&`RnHF_*6&C8P%@Z4|3a%zFaq= z56$TG_SFxzOod!qI21YW6@Rx*o>dbipKXdcF}*PNMc)$}atpp}?(Vy2ONj{Tzm)D5 z96g#b^Y@KAwybE?tCOb-Pql`XW%Pa%^xIJNsOtBxYPO6<%zU?P;o`aHuGcH;tGsuP z1x}V?#CK~(`5fEqvSy=$u%d`&)D zj2f2^HcKpd5B(y48DK4yEQ~!+r`USwwtLv72XLz`w8-;um-NwVc@d1 z)g?lx2kBjA`KseGsa|`Dd#v=#Kl20w)Nzk(Rz$&f0Ot1>$#_eK>YqLa zp=%zjGtx`)04{5BOLxHC69A5eq&6rI>9h>GHy+|G9jZ2(3Y&C00`SApkX)owGo)+f zPsge{E>x)us_6B+HA7T963LXR3nP>xfutwpd1o@I4sPHr6|45SP%#rYjFE~*0^=D~ zrQ66`DpXZmBx2J1%%27&?tW<44wm!oL%`Dp&(jwLLHb!9>@tyz1pUAj;(p?1J6q22 frv!QuKeZm|bFo5|!n+axa`^oVY=Ktzt^oW4rFz8L diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testDoNotCountSizeTheSameWorkspaceTwice.zip b/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testDoNotCountSizeTheSameWorkspaceTwice.zip index 3cb38fa72ffca1b22cba7a313820a23ee5c43bcd..941b9d8ad413232e23181c16197dc8c3068fea0d 100644 GIT binary patch literal 7595 zcmWIWW@h1H00Hj=-7qi%N^mpCFqG#PWfvDDCZ`(ehlX%6F#CEOOa|f73T_5QmY2*7 z3}7Mvry-)KhQQ4u(>OU?#uXIhXQd{W7?EIZ@SnhRCZJzISeKx=d8rj8PNkVSDSoB7 zNvTEf&`8XB8HyGfhFrMALzSRKNgzv#3Hn0>=xPpz8(Eyrvu?fEs|n3S8pIbf&oJY@-rS|A;S7M`gS zeEp9o2(-QbE1IHjd-K&<=2YS96_=akKl&uTStN3TC+E*kzT8_9dq38F;Ayt0J0BOr zaPp|Z7W2EM+6pr=VrR5{d;9g_t8KQc+|+vJCv3`UnQ$vbFL*x(cglsOuQYD{4>SGC zHmjzyWW{$IHQR}@xJKu@&oa^!;V)aovSjO zdePeIeU<0^z~x(_Hr?O9@h2l9HsxxV_u*@s@I&v<@4siXJsl=oVVLanoBJU?om_4U$y`ZEHXsAD08$vSRGhl7_(`ws+0AN9Qiiq0KP#+Y3@Y?VK6>GyDv!;t0n*`*1 z&IyF7&yu;q2dxzK7%8X}4fP=f65+-w_5z7eF^n*u`UMfhMWj{?s4k*)#XzW00&@*1 z#Un5o!U3U13Br7eN-si<5)5l-QHr5ghQy{lNS+)FjS@sKQ8#?BSILALB?#Bhwo!s< z54FnzMkYCC>|wyoAOX!Q0t|m0K}>kJAC%=-A;So0oxA{V+y;uG80d;>Alz)SjFv+& zdI~P1k%kwDb3STw3KAZ`E-}NF#y14*z-U|%XC=^FI8a6LRw&SBcrY32!j6% of2RDz`VdwZk&_)!>%X}q+esjFS%H-}1A{ye#sL$Gxd4a<0Cy#4bpQYW literal 7595 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 H*8unzyTBS{ diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testExecute.zip b/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testExecute.zip index d294d4ccd2e5188a1648a9997838d0e36c831c3f..3ff2633463dd4318fa2912af01ae9a4b4a50fda5 100644 GIT binary patch literal 11904 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 H*8unzyTBS{ diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testExecuteMatrixProject.zip b/src/test/resources/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest/testExecuteMatrixProject.zip index 0c6ba75ddb543fd1fcc8dec5c7cea9abb6bdd606..cb3e1c4d2df4ea2d6398ac23a6c139fc1982bbea 100644 GIT binary patch literal 39178 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 From 41013205debadc71fd4b842aae9058dfe6224bb4 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 13 Jan 2023 15:05:40 +0000 Subject: [PATCH 014/158] Removes bash script to migrate all test zip files --- fix_zips.sh | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100755 fix_zips.sh diff --git a/fix_zips.sh b/fix_zips.sh deleted file mode 100755 index 6664f074..00000000 --- a/fix_zips.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -# TO CLEAN -# find src/test/resources -name \*old -delete -# git restore src/test/resources/ - -for ZIP_FILE in $(find src -name \*zip |sort ); do - ZIP_FILE=$(realpath $ZIP_FILE) - echo "$ZIP_FILE" - - TEMP_DIR=$(mktemp -d) - unzip -q $ZIP_FILE -d $TEMP_DIR - - OLD_ZIP_FILE="$(dirname $ZIP_FILE)/$(basename $ZIP_FILE).old" - mv $ZIP_FILE $OLD_ZIP_FILE - - find "$TEMP_DIR" -name "*~" -delete - - for PROJECT_DIR in $(find "$TEMP_DIR" -name config.xml -not -path "*/axis/*" |sort| xargs dirname); do - echo $PROJECT_DIR - DISK_USAGE_FILE="$PROJECT_DIR/disk-usage.xml" - - BUILD_NUMBER=1 - for BUILD_DIR in $(find "$PROJECT_DIR/builds" -mindepth 1 -maxdepth 1 -type d|sort); do - OLD_BUILD_NUMBER=$(basename "$BUILD_DIR") - xmlstarlet ed --inplace \ - -u '/build/number' \ - -v $BUILD_NUMBER \ - "$BUILD_DIR/build.xml" - mv -v "$BUILD_DIR" "$PROJECT_DIR/builds/$BUILD_NUMBER" - if test -f "$DISK_USAGE_FILE"; then - xmlstarlet ed --inplace \ - -u "//hudson.plugins.disk__usage.DiskUsageBuildInformation[id='$OLD_BUILD_NUMBER']/number" \ - -v $BUILD_NUMBER \ - "$DISK_USAGE_FILE" - xmlstarlet ed --inplace \ - -u "//hudson.plugins.disk__usage.DiskUsageBuildInformation[id='$OLD_BUILD_NUMBER']/id" \ - -v $BUILD_NUMBER \ - "$DISK_USAGE_FILE" - fi - ((BUILD_NUMBER=BUILD_NUMBER+1)) - done - if test -f "$PROJECT_DIR/nextBuildNumber"; then - echo $BUILD_NUMBER > "$PROJECT_DIR/nextBuildNumber" - fi - done - - pushd "$TEMP_DIR" - zip -q -r $ZIP_FILE . - popd - rm -r "$TEMP_DIR" -done \ No newline at end of file From 458a180adfea874b817466d98ea4c0ceb9b3d538 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 13 Jan 2023 16:33:40 +0000 Subject: [PATCH 015/158] Bump parent pom and Jenkins to 1.607 Jenkins 1.607 changed the way to add nodes and is not really possible to changed the remoteFS from a existing node. --- pom.xml | 2 +- .../plugins/disk_usage/integration/DiskUsagePropertyTest.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 7c188d06..ae542d4f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.597 + 1.607 disk-usage diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index f295de62..d929b4aa 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -212,10 +212,6 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep //take one slave offline slave1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); - //change remote fs - slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(),"ChangedWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); - customWorkspaceSlaveSize = customWorkspaceSlaveSize + workspaceSlave1.length(); - assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); } @Test From 968353643dbe7ba69d98910d385423a4f8746991 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 13 Jan 2023 17:48:27 +0000 Subject: [PATCH 016/158] Bump parent pom and Jenkins to 1.645 Adds plugins detached from Jenkins core Adds Eclipse sisu as managed dependency due to: > java.lang.IncompatibleClassChangeError: Implementing class --- pom.xml | 22 ++++++++++++- .../integration/DiskUsageUtilTest.java | 4 +-- .../JobDiskUsageCalculationThreadTest.java | 33 +++++++++++-------- ...rkspaceDiskUsageCalculationThreadTest.java | 4 +-- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index ae542d4f..750aeec3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.607 + 1.645 disk-usage @@ -33,8 +33,28 @@ mailer 1.8 + + org.jenkins-ci.plugins + matrix-project + 1.0 + + + org.jenkins-ci.plugins + junit + 1.0 + + + + + org.eclipse.sisu + org.eclipse.sisu.plexus + 0.0.0.M3 + + + + diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 29002a34..4fd904df 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -143,7 +143,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = j.createMatrixProject("project1"); + MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); @@ -218,7 +218,7 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = j.createMatrixProject("project1"); + MatrixProject project1 = j.jenkins.createProject(MatrixProject.class,"project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 5dabb34c..80328f48 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -1,5 +1,8 @@ package hudson.plugins.disk_usage.integration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import hudson.plugins.disk_usage.*; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; @@ -19,16 +22,20 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; +import org.junit.Rule; import org.junit.Test; -import org.jvnet.hudson.test.HudsonTestCase; +import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ -public class JobDiskUsageCalculationThreadTest extends HudsonTestCase{ - +public class JobDiskUsageCalculationThreadTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + private void waitUntilThreadEnds(JobWithoutBuildsDiskUsageCalculation calculation) throws InterruptedException{ while(calculation.isExecuting()){ Thread.sleep(100); @@ -60,10 +67,10 @@ private Long getSize(List files){ public void testExecute() throws IOException, InterruptedException{ //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); - jenkins.getExtensionList(RunListener.class).remove(listener); + j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); - FreeStyleProject project = (FreeStyleProject) jenkins.getItem("project1"); - FreeStyleProject project2 = (FreeStyleProject) jenkins.getItem("project2"); + FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); + FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); //we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -89,10 +96,10 @@ public void testMatrixProject() throws IOException, InterruptedException{ //turn off run listener DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); - jenkins.getExtensionList(RunListener.class).remove(listener); + j.jenkins.getExtensionList(RunListener.class).remove(listener); Map matrixConfigurationsSize = new TreeMap(); - MatrixProject project = (MatrixProject) jenkins.getItem("project1"); - FreeStyleProject project2 = (FreeStyleProject) jenkins.getItem("project2"); + MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); + FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); //we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -124,7 +131,7 @@ public void testMatrixProject() throws IOException, InterruptedException{ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception{ JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); DiskUsageTestUtil.cancelCalculation(calculation); - FreeStyleProject project = jenkins.createProject(FreeStyleProject.class, contextPath); + FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, j.contextPath); final JobWithoutBuildsDiskUsageCalculation testCalculation = new JobWithoutBuildsDiskUsageCalculation(); Thread t = new Thread(testCalculation.getThreadName()){ @Override @@ -144,7 +151,7 @@ public void run(){ } public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ - FreeStyleProject projectWithoutDiskUsage = jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); + FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); DiskUsageProjectActionFactory.DESCRIPTOR.disableJobsDiskUsageCalculation(); JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); calculation.execute(TaskListener.NULL); @@ -157,8 +164,8 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); if(calculation.isExecuting()) DiskUsageTestUtil.cancelCalculation(calculation); - FreeStyleProject exludedJob = jenkins.createProject(FreeStyleProject.class, "excludedJob"); - FreeStyleProject includedJob = jenkins.createProject(FreeStyleProject.class, "incudedJob"); + FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); + FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); List excludes = new ArrayList(); excludes.add(exludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index f7cc3b71..b4709f17 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -142,11 +142,11 @@ public void testExecuteMatrixProject() throws Exception { AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = j.createMatrixProject("project1"); + MatrixProject project1 = j.jenkins.createProject(MatrixProject.class,"project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); - MatrixProject project2 = j.createMatrixProject("project2"); + MatrixProject project2 = j.jenkins.createProject(MatrixProject.class,"project2"); AxisList axes2 = new AxisList(); TextAxis axis2 = new TextAxis("axis","axis1 axis2"); axes2.add(axis2); From 19442b75b5e199e388cd88f0366b3ae9f9498b7a Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 13 Jan 2023 18:00:43 +0000 Subject: [PATCH 017/158] Bump parent pom from 1.645 to 2.37 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 750aeec3..354dcc29 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.645 + 2.37 disk-usage From 20e8c8bbe3f1e0de71b40528bc3bd8d6361f724f Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 16:17:24 +0000 Subject: [PATCH 018/158] Bump Jenkins to 2.13 Removed adding property to build in constructor due to NullPointerException in new line getNextBuildNumber() in LazyBuildMixIn onLoad https://github.com/jenkinsci/jenkins/compare/jenkins-2.12...jenkins-2.13#diff-0e1a882c198d61779bcda4d693edb63fe88cbbdacb68ec4f4181219bc4b4c859R106 --- pom.xml | 4 ++++ .../hudson/plugins/disk_usage/BuildDiskUsageAction.java | 8 +------- .../hudson/plugins/disk_usage/DiskUsageCalculation.java | 8 ++++++-- .../java/hudson/plugins/disk_usage/DiskUsageUtil.java | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 354dcc29..038a92da 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,10 @@ HEAD + + 2.13 + + org.jenkins-ci.plugins diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index c0dc6df3..e5743531 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -32,13 +32,7 @@ public class BuildDiskUsageAction implements ProminentProjectAction, BuildBadgeA DiskUsage diskUsage; public BuildDiskUsageAction(AbstractBuild build) { - this.build = build; - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - if(property==null){ - DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - } - DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); + this.build = build; } public String getIconFileName() { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 50d06681..cdf3c72b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -10,6 +10,7 @@ import hudson.triggers.Trigger; import java.util.Calendar; import java.util.GregorianCalendar; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -79,8 +80,11 @@ public long getInitialDelay(){ @Override public boolean cancel(){ cancelled = true; - ScheduledThreadPoolExecutor ex = (ScheduledThreadPoolExecutor) Timer.get(); - ex.purge(); + final ScheduledExecutorService scheduledExecutorService = Timer.get(); + if (scheduledExecutorService instanceof ScheduledThreadPoolExecutor){ + ScheduledThreadPoolExecutor ex = (ScheduledThreadPoolExecutor) scheduledExecutorService; + ex.purge(); + } return super.cancel(); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index dbdc0336..140186ad 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -449,13 +449,13 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr else{ if(build!=null){ information = new DiskUsageBuildInformation(buildId, build.getTimeInMillis(), build.getNumber(), buildSize); - property.getDiskUsageOfBuilds().add(information); + property.getDiskUsage().addBuildInformation(information, build); } else{ //should not happen AbstractBuild newLoadedBuild = (AbstractBuild) project._getRuns().getById(buildId); information = new DiskUsageBuildInformation(buildId, newLoadedBuild.getTimeInMillis(), newLoadedBuild.getNumber(), buildSize); - property.getDiskUsageOfBuilds().add(information); + property.getDiskUsage().addBuildInformation(information, build); } } property.saveDiskUsage(); From 8aded16a4ede149c830644737dbc4feb7bdcd288 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 16:24:00 +0000 Subject: [PATCH 019/158] Update parent pom from 2.37 to 3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 038a92da..2f3a664a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 2.37 + 3.0 disk-usage From 22e4271f36d4f07e56393fb2c4c7fa8fd6c66c46 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 16:31:41 +0000 Subject: [PATCH 020/158] Removes jenkins version property and use from Jenkins 2.60.1 from parent --- pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pom.xml b/pom.xml index 2f3a664a..ea183338 100644 --- a/pom.xml +++ b/pom.xml @@ -27,10 +27,6 @@ HEAD - - 2.13 - - org.jenkins-ci.plugins From eb4ff5ce0e36a8569d5d60e5505d244b1fa6841e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 16:44:12 +0000 Subject: [PATCH 021/158] Update parent pom to 3.1 and set required java version to 8 --- pom.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea183338..22902232 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 3.0 + 3.1 disk-usage @@ -27,6 +27,10 @@ HEAD + + 8 + + org.jenkins-ci.plugins From 76b496b1fc9c112fe8e187f3ca5869ac86a9922a Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 17:04:00 +0000 Subject: [PATCH 022/158] Update parent pom from 3.1 to 3.57 Implicit upgrade to Jenkin 2.138.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 22902232..f05959e8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 3.1 + 3.57 disk-usage From 7c844c4eb58a24f9f9c0fddf2ec3aa6abe611ce9 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 17:12:09 +0000 Subject: [PATCH 023/158] Removes managed plugin access-modifier-checker and inherit it from parent --- pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pom.xml b/pom.xml index f05959e8..8cf12724 100644 --- a/pom.xml +++ b/pom.xml @@ -95,15 +95,6 @@ - - - - org.kohsuke - access-modifier-checker - 1.7 - - - From 7d00a8dd5063d02bc9fcb4526576da3d183ab924 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 17:22:45 +0000 Subject: [PATCH 024/158] Upgrades surefire to 3.0.0-M4 Keeps the reuseForks false, due to several tests not being truly independent --- pom.xml | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 8cf12724..3ef3b57c 100644 --- a/pom.xml +++ b/pom.xml @@ -63,31 +63,12 @@ maven-surefire-plugin - 2.16 - - - default-test - test - - test - - - - - hudson.udp - 33849 - - - false - 2 - - - + 3.0.0-M4 hudson.udp - 33849 + -1 false From 115976a834923ec9dee9e42ffdc93731929670b9 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 17:49:39 +0000 Subject: [PATCH 025/158] Update parent pom from 3.57 to 4.0 Implicit update to Jenkins 2.204 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3ef3b57c..fe2bb63a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 3.57 + 4.0 disk-usage From 8d3301176cb68d2625b45510b8ea9b86f6fab156 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 14 Jan 2023 18:00:46 +0000 Subject: [PATCH 026/158] Update parent pom from 4.0 to 4.41 Implicit update to Jenkins 2.249 Update tests to create remoteFS due to: https://github.com/jenkinsci/jenkins-test-harness/pull/428 --- pom.xml | 2 +- .../plugins/disk_usage/integration/DiskUsagePropertyTest.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe2bb63a..4d775475 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.0 + 4.41 disk-usage diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index d929b4aa..ebcda5c7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -149,6 +149,8 @@ public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception{ project.addProperty(property); Slave slave1 = j.createOnlineSlave(); Slave slave2 = j.createOnlineSlave(); + slave1.getWorkspaceRoot().mkdirs(); + slave2.getWorkspaceRoot().mkdirs(); FilePath path = j.jenkins.getWorkspaceFor(project); path.mkdirs(); property.putSlaveWorkspaceSize(j.jenkins, path.getRemote(), 10495l); @@ -168,6 +170,8 @@ public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception{ project.addProperty(property); Slave slave1 = j.createOnlineSlave(); Slave slave2 = j.createOnlineSlave(); + slave1.getWorkspaceRoot().mkdirs(); + slave2.getWorkspaceRoot().mkdirs(); FilePath path = j.jenkins.getWorkspaceFor(project); path.mkdirs(); property.putSlaveWorkspaceSize(j.jenkins, path.getRemote(), 10495l); From 0f6d50b5b680640132a325b463f6ab38f9eb0dd4 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 15 Jan 2023 15:52:00 +0000 Subject: [PATCH 027/158] Update parent pom from 4.41 to 4.51 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4d775475..f1efa273 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.41 + 4.51 disk-usage From 2a07defd132949ceb68ea6050deb223ae61c21d3 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 15 Jan 2023 16:04:40 +0000 Subject: [PATCH 028/158] Update parent pom from 4.51 to 4.53 and to Java 11 Implicit upgrade to Jenkins 2.361 JavaMail was detached from Jenkins in 2.331 https://github.com/jenkinsci/jenkins/pull/6165 https://www.jenkins.io/blog/2022/12/14/require-java-11/ --- Jenkinsfile | 6 ++++++ pom.xml | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..22a78e9b --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,6 @@ +buildPlugin( + useContainerAgent: true, + configurations: [ + [platform: 'linux', jdk: 17], + [platform: 'windows', jdk: 11], +]) diff --git a/pom.xml b/pom.xml index f1efa273..2dd25c93 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.51 + 4.53 disk-usage @@ -28,7 +28,7 @@ - 8 + 11 @@ -47,6 +47,11 @@ junit 1.0 + + io.jenkins.plugins + javax-mail-api + 1.6.2-8 + From ddb7bfbff526c7e7a43c6358d1b185a8638b7895 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 15 Jan 2023 16:27:32 +0000 Subject: [PATCH 029/158] Removes Managed Eclipse sisu no longer needed --- pom.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd25c93..3c8989ef 100644 --- a/pom.xml +++ b/pom.xml @@ -54,16 +54,6 @@ - - - - org.eclipse.sisu - org.eclipse.sisu.plexus - 0.0.0.M3 - - - - From d3b394034ed4c86e33758d284cad506f5cb6464a Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 21 Jan 2023 15:07:38 +0000 Subject: [PATCH 030/158] Make unit tests work in Windows --- .../integration/DiskUsageBuildListenerTest.java | 8 +++++++- .../integration/DiskUsagePropertyTest.java | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index 4952ca6e..ab121694 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -4,6 +4,8 @@ */ package hudson.plugins.disk_usage.integration; +import hudson.Functions; +import hudson.tasks.BatchFile; import hudson.tasks.Shell; import java.io.File; import hudson.FilePath; @@ -40,7 +42,11 @@ public void testOnDeleted() throws Exception{ @Test public void testOnCompleted() throws Exception{ FreeStyleProject project = j.createFreeStyleProject(); - project.getBuildersList().add(new Shell("echo ahoj > log.log")); + if (Functions.isWindows()){ + project.getBuildersList().add(new BatchFile("echo ahoj > log.log")); + } else { + project.getBuildersList().add(new Shell("echo ahoj > log.log")); + } j.buildAndAssertSuccess(project); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Build information is cached.", property.getDiskUsageBuildInformation(1)); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index ebcda5c7..dbbb778b 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -1,6 +1,8 @@ package hudson.plugins.disk_usage.integration; +import hudson.Functions; +import hudson.tasks.BatchFile; import java.util.ConcurrentModificationException; import java.util.GregorianCalendar; import hudson.model.FreeStyleBuild; @@ -190,7 +192,11 @@ public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception{ @Test public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Exception{ FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - project.getBuildersList().add(new Shell("echo hello > log")); + if (Functions.isWindows()){ + project.getBuildersList().add(new BatchFile("echo hello > log")); + } else { + project.getBuildersList().add(new Shell("echo hello > log")); + } Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(),"SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave slave1 = j.createOnlineSlave(); Slave slave2= j.createOnlineSlave(); @@ -221,7 +227,11 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep @Test public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception{ FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - project.getBuildersList().add(new Shell("echo hello > log")); + if (Functions.isWindows()){ + project.getBuildersList().add(new BatchFile("echo hello > log")); + } else { + project.getBuildersList().add(new Shell("echo hello > log")); + } Slave slave1 = j.createOnlineSlave(); File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(),"custom2/log"); From b3daead7874616a1c66afc7589d91708c7e981fa Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 22 Jan 2023 01:53:41 +0000 Subject: [PATCH 031/158] Adds builder to jobs in unit test to have some used disk space This test was only green in Linux, due to directory having non zero size, and failing in Windows that reports zero for directories. Adds some builder to have some actual used disk. --- .../WorkspaceDiskUsageCalculationThreadTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index b4709f17..c7758089 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import hudson.Functions; import hudson.plugins.disk_usage.*; import hudson.matrix.AxisList; import hudson.matrix.MatrixProject; @@ -24,6 +25,8 @@ import hudson.slaves.DumbSlave; import hudson.slaves.NodeProperty; import hudson.slaves.RetentionStrategy; +import hudson.tasks.BatchFile; +import hudson.tasks.Shell; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -261,6 +264,13 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); FreeStyleProject excludedJob = j.getInstance().createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.getInstance().createProject(FreeStyleProject.class, "incudedJob"); + if (Functions.isWindows()){ + excludedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); + includedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); + } else { + excludedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); + includedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); + } Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); excludedJob.setAssignedLabel(slave1.getSelfLabel()); includedJob.setAssignedLabel(slave1.getSelfLabel()); From d9a51a5bd1aaf9c487139d56bf05922c857aa9c8 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:36:37 +0000 Subject: [PATCH 032/158] Clean code using openrewrite RemoveExtraSemicolons recipe --- .../java/hudson/plugins/disk_usage/DiskUsageBuildListener.java | 2 +- .../hudson/plugins/disk_usage/DiskUsageCalculationTest.java | 2 +- .../disk_usage/integration/BuildDiskUsageActionTest.java | 2 +- .../plugins/disk_usage/integration/DiskUsagePropertyTest.java | 2 +- .../disk_usage/integration/ProjectDiskUsageActionTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java index 65f46b4c..ea0ab3bb 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java @@ -33,7 +33,7 @@ public void onDeleted(AbstractBuild build){ property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); - if(information!=null){; + if(information!=null){ property.getDiskUsage().removeBuild(information); property.getDiskUsage().save(); } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 6faed651..fcaff71b 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -104,7 +104,7 @@ public void testGetRecurrencePeriod(){ calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + (calendar.get(Calendar.MONTH) + 1) + " " + dayOfWeek, false); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - calendar.setTimeInMillis(System.currentTimeMillis() + period);; + calendar.setTimeInMillis(System.currentTimeMillis() + period); assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index c753755e..d826396e 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -77,7 +77,7 @@ public void getBuildUsageStringMatrixProject() throws Exception{ matrixProject.setAxes(list); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild = matrixProject.getLastBuild(); - matrixProject.setAxes(list);; + matrixProject.setAxes(list); Long kiloBytes = 2048l; int count = 0; for(MatrixConfiguration c: matrixProject.getItems()){ diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index dbbb778b..f598898d 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -364,7 +364,7 @@ public void testCheckWorkspacesWithLoadingBuilds() throws IOException { @Test public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ -; FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); + FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); TextAxis axis2 = new TextAxis("axis2", "Aaxis", "Baxis", "Caxis"); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 324da2b5..9c348df8 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -212,7 +212,7 @@ public TopLevelItemDescriptor getDescriptor() { } public void update(){ - this.updateTransientActions();; + this.updateTransientActions(); } @Override From bfd0eb6ff051d568aba7beec968363e6577353e7 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:38:09 +0000 Subject: [PATCH 033/158] Clean code using openrewrite UnnecessaryParentheses recipe --- .../plugins/disk_usage/DiskUsageOvearallGraphGenerator.java | 2 +- src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java | 4 ++-- .../plugins/disk_usage/DiskUsageProjectActionFactory.java | 2 +- src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java | 2 +- .../hudson/plugins/disk_usage/ProjectDiskUsageAction.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 6b217c54..5b36efe3 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -77,7 +77,7 @@ public Long getBuildsDiskUsage(){ public Long getJobsDiskUsage(){ if(jobsWithoutBuildsUsage==null) return getBuildsDiskUsage(); - return (jobsWithoutBuildsUsage + getBuildsDiskUsage()); + return jobsWithoutBuildsUsage + getBuildsDiskUsage(); } public Long getAllSpace(){ diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 7047b889..6d148285 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -62,7 +62,7 @@ public Long getCashedGlobalBuildsDiskUsage(){ } public Long getCashedGlobalJobsDiskUsage(){ - return (diskUsageBuilds + diskUsageJobsWithoutBuilds); + return diskUsageBuilds + diskUsageJobsWithoutBuilds; } public Long getCashedGlobalJobsWithoutBuildsDiskUsage(){ @@ -92,7 +92,7 @@ public Long getGlobalBuildsDiskUsage() throws IOException{ public Long getGlobalJobsDiskUsage() throws IOException{ refreshGlobalInformation(); - return (diskUsageBuilds + diskUsageJobsWithoutBuilds); + return diskUsageBuilds + diskUsageJobsWithoutBuilds; } public Long getGlobalJobsWithoutBuildsDiskUsage() throws IOException{ diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index db61c937..888bbe66 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -96,7 +96,7 @@ public Long getCashedGlobalBuildsDiskUsage(){ } public Long getCashedGlobalJobsDiskUsage(){ - return (diskUsageBuilds + diskUsageJobsWithoutBuilds); + return diskUsageBuilds + diskUsageJobsWithoutBuilds; } public Long getCashedGlobalJobsWithoutBuildsDiskUsage(){ diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index 0ffcfd8a..373407b1 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -45,7 +45,7 @@ public Long getSlaveWorkspacesUsage(){ public Long getJobsDiskUsage(){ if(diskUsageJobsWithoutBuilds==null) return getBuildsDiskUsage(); - return (diskUsageJobsWithoutBuilds + getBuildsDiskUsage()); + return diskUsageJobsWithoutBuilds + getBuildsDiskUsage(); } public Long getAllSpace(){ diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index c5accfb8..d909985d 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -307,7 +307,7 @@ public Graph getGraph() throws IOException { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset dataset2 = new DefaultCategoryDataset(); for (Object[] usage : usages) { - Integer label = ((Integer) usage[0]); + Integer label = (Integer) usage[0]; dataset.addValue(((Long) usage[1]) / base, Messages.DiskUsage_Graph_JobDirectory(), label); dataset.addValue(((Long) usage[2]) / base, From 9b045d1c4c48ee6f74dad85e59e1a631061a5506 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:42:23 +0000 Subject: [PATCH 034/158] Clean code using openrewrite UseJavaStyleArrayDeclarations recipe --- src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 140186ad..129b7dba 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -204,7 +204,7 @@ public static void controlWorkspaceExceedSize(AbstractProject project){ public static List parseExcludedJobsFromString(String jobs){ List list = new ArrayList(); - String jobNames[] = jobs.split(","); + String[] jobNames = jobs.split(","); for(String name: jobNames){ name = name.trim(); Item item = Jenkins.getInstance().getItem(name); From 647cea4d851420fa9830eb508ae7e7a8f5b8206e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:45:44 +0000 Subject: [PATCH 035/158] Clean code using openrewrite EmptyNewlineAtEndOfFile recipe --- src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java | 2 -- src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 2505a89e..dcccc1a9 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -507,5 +507,3 @@ public boolean isApplicable(Class jobType) { public static final Logger LOGGER = Logger.getLogger(DiskUsageProperty.class.getName()); } - - diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index 373407b1..095ae242 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -71,4 +71,3 @@ public String toString(){ }; } } - From 46aa2fcde6c5c6cf023cb186aaca9b0e51b5074d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:53:57 +0000 Subject: [PATCH 036/158] Clean code using openrewrite NoWhitespaceAfter recipe --- src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 129b7dba..e248af3f 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -151,7 +151,7 @@ public static void sendEmail(String subject, String message) throws MessagingExc public static Long getSizeInBytes(String stringSize){ if(stringSize==null || stringSize.equals("-")) return 0l; - String []values = stringSize.split(" "); + String[] values = stringSize.split(" "); int index = getIndex(values[1]); Long value = Long.decode(values[0]); Double size = value * (Math.pow(1024, index)); From fae1685f486a6d02ca0be3bda96cd6689af81288 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 23 Jan 2023 23:57:17 +0000 Subject: [PATCH 037/158] Clean code using openrewrite NoWhitespaceBefore recipe --- .../disk_usage/BuildDiskUsageAction.java | 8 ++-- .../disk_usage/DiskUsageBuildInformation.java | 2 +- .../disk_usage/DiskUsageBuildListener.java | 2 +- .../plugins/disk_usage/DiskUsageGraph.java | 14 +++---- .../plugins/disk_usage/DiskUsagePlugin.java | 2 +- .../plugins/disk_usage/DiskUsageProperty.java | 2 +- .../plugins/disk_usage/DiskUsageUtil.java | 16 +++---- .../plugins/disk_usage/ProjectDiskUsage.java | 10 ++--- .../disk_usage/ProjectDiskUsageAction.java | 2 +- .../integration/BuildDiskUsageActionTest.java | 6 +-- .../BuildDiskUsageCalculationThreadTest.java | 4 +- .../DiskUsageBuildListenerTest.java | 4 +- .../integration/DiskUsagePluginTest.java | 6 +-- .../integration/DiskUsagePropertyTest.java | 24 +++++------ .../integration/DiskUsageUtilTest.java | 42 +++++++++---------- .../ProjectDiskUsageActionTest.java | 10 ++--- .../integration/ProjectDiskUsageTest.java | 2 +- ...rkspaceDiskUsageCalculationThreadTest.java | 38 ++++++++--------- 18 files changed, 97 insertions(+), 97 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index e5743531..d6bf3775 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -81,7 +81,7 @@ public Long getAllDiskUsage(){ Long buildsDiskUsage = getDiskUsage(); AbstractProject project = build.getProject(); if(project instanceof ItemGroup){ - buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup)project); + buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) project); } return buildsDiskUsage; } @@ -94,7 +94,7 @@ private Long getBuildsDiskUsageAllSubItems(ItemGroup group){ Long buildsDiskUsage = 0l; for(Object item: group.getItems()){ if(item instanceof ItemGroup){ - buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup)item); + buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) item); } else{ if(item instanceof AbstractProject){ @@ -125,7 +125,7 @@ public Object readResolve() { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); AbstractProject project = build.getProject().getRootProject(); if(property!=null && (project instanceof TopLevelItem)) - property.putSlaveWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem)project).getRemote(), diskUsage.wsUsage); + property.putSlaveWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); } diskUsage=null; } @@ -165,7 +165,7 @@ public void onLoad(Run r) { } //Transient actions can be created even during deletion of job if(property.getDiskUsageBuildInformation(build.getNumber())==null && build.getRootDir().exists()){ - property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(),build.getTimeInMillis(), build.getNumber(), size), build); + property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index 3787703d..a2f7b93c 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -70,7 +70,7 @@ public boolean equals(Object o){ public int compareTo(Object o){ if(o instanceof DiskUsageBuildInformation){ - return id.compareTo(((DiskUsageBuildInformation)o).getId()); + return id.compareTo(((DiskUsageBuildInformation) o).getId()); } throw new IllegalArgumentException("Can not compare with different type"); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java index ea0ab3bb..f973aabc 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java @@ -48,7 +48,7 @@ public void onStarted(AbstractBuild build, TaskListener listener){ } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); if(information==null){ - property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(),build.getTimeInMillis(), build.getNumber(), 0l), build); + property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), 0l), build); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java index 82dbd32b..dd8af15b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java @@ -34,7 +34,7 @@ public class DiskUsageGraph extends Graph{ String workspaceUnit; public DiskUsageGraph(CategoryDataset dataset, String unit, CategoryDataset workspaceDataset, String workspaceUnit){ - super(-1,350,150); + super(-1, 350, 150); this.workspaceDataset = workspaceDataset; this.dataset = dataset; this.unit = unit; @@ -80,21 +80,21 @@ protected JFreeChart createGraph() { ValueAxis rangeAxis = new NumberAxis(Messages.DiskUsage_Graph_WorkspaceDiskUsageAxis() + " [" + workspaceUnit + "]"); plot.setRangeAxis(1, rangeAxis); plot.mapDatasetToRangeAxis(1, 1); - setColorForArea(plot.getRenderer(), dataset.getRowCount()>2); + setColorForArea(plot.getRenderer(), dataset.getRowCount() > 2); plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); - renderer.setSeriesPaint(1, new Color(255,204,0)); + renderer.setSeriesPaint(1, new Color(255, 204, 0)); return chart; } public void setColorForArea(CategoryItemRenderer renderer, boolean global){ if(global){ renderer.setSeriesPaint(0, Color.LIGHT_GRAY); - renderer.setSeriesPaint(1, new Color(60,179,113)); - renderer.setSeriesPaint(2, new Color(106,90,205)); + renderer.setSeriesPaint(1, new Color(60, 179, 113)); + renderer.setSeriesPaint(2, new Color(106, 90, 205)); } else{ - renderer.setSeriesPaint(0, new Color(60,179,113)); - renderer.setSeriesPaint(1, new Color(106,90,205)); + renderer.setSeriesPaint(0, new Color(60, 179, 113)); + renderer.setSeriesPaint(1, new Color(106, 90, 205)); } } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 6d148285..60c716a6 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -190,7 +190,7 @@ public Graph getOverallGraph(){ //First iteration just to get scale of the y-axis for (DiskUsageOvearallGraphGenerator.DiskUsageRecord usage : record){ if(getConfiguration().getShowFreeSpaceForJobDirectory()){ - maxValue = Math.max(maxValue,usage.getAllSpace()); + maxValue = Math.max(maxValue, usage.getAllSpace()); } maxValue = Math.max(maxValue, usage.getJobsDiskUsage()); maxValueWorkspace = Math.max(maxValueWorkspace, usage.getSlaveWorkspacesUsage()); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index dcccc1a9..5d73f42f 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -272,7 +272,7 @@ public void checkWorkspaces(boolean force) { if(node.toComputer()!=null && node.toComputer().isOnline()){ FilePath path =null; try{ - path = node.getWorkspaceFor((TopLevelItem)owner); + path = node.getWorkspaceFor((TopLevelItem) owner); if(path!=null && path.exists() && (diskUsage.slaveWorkspacesUsage.get(node.getNodeName())==null || !diskUsage.slaveWorkspacesUsage.get(node.getNodeName()).containsKey(path.getRemote()))){ putSlaveWorkspace(node, path.getRemote()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index e248af3f..47fa0fec 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -65,7 +65,7 @@ public static void addProperty(Item item){ } if(item instanceof ItemGroup){ - for(AbstractProject project : DiskUsageUtil.getAllProjects((ItemGroup)item)){ + for(AbstractProject project : DiskUsageUtil.getAllProjects((ItemGroup) item)){ DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property==null){ try { @@ -98,12 +98,12 @@ public static Date getDate(String timeCount, String timeUnit){ return null; int unit = Integer.decode(timeUnit); int count = Integer.decode(timeCount); - return getDate(unit,count); + return getDate(unit, count); } public static Date getDate(int unit, int count){ Calendar calendar = new GregorianCalendar(); - calendar.set(unit, calendar.get(unit)-count); + calendar.set(unit, calendar.get(unit) - count); return calendar.getTime(); } @@ -308,7 +308,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); if(paths!=null && !paths.isEmpty()){ for(String path: paths.keySet()){ - exceededFiles.add(new FilePath(node.getChannel(),path)); + exceededFiles.add(new FilePath(node.getChannel(), path)); } } } @@ -316,7 +316,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener property.checkWorkspaces(); listener.getLogger().println("Started calculate disk usage of workspace"); Long startTimeOfWorkspaceCalculation = System.currentTimeMillis(); - Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(),exceededFiles); + Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(), exceededFiles); listener.getLogger().println("Finished Calculation of disk usage of workspace in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfWorkspaceCalculation)); property.putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); property.saveDiskUsage(); @@ -476,7 +476,7 @@ public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayL diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); } catch(Exception e){ - Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage fails to calculate workspace for file path " + workspace.getRemote() + " through channel " + workspace.getChannel(),e); + Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage fails to calculate workspace for file path " + workspace.getRemote() + " through channel " + workspace.getChannel(), e); } } return diskUsage; @@ -525,7 +525,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); if(paths!=null && !paths.isEmpty()){ for(String path: paths.keySet()){ - exceededFiles.add(new FilePath(node.getChannel(),path)); + exceededFiles.add(new FilePath(node.getChannel(), path)); } } } @@ -549,7 +549,7 @@ public static List getAllProjects(ItemGroup ite List items = new ArrayList(); for (Item item : itemGroup.getItems()) { if(item instanceof AbstractProject){ - items.add((AbstractProject)item); + items.add((AbstractProject) item); } if (item instanceof ItemGroup) { items.addAll(getAllProjects((ItemGroup) item)); diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 16061462..cda6601a 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -66,7 +66,7 @@ public Set getBuildDiskUsage(boolean needAll){ loadAllBuilds(); } catch(Exception e){ - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load builds "+getConfigFile(),e); + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load builds " + getConfigFile(), e); } } information.addAll(buildDiskUsage); @@ -79,7 +79,7 @@ public synchronized void save() { getConfigFile().write(this); SaveableListener.fireOnChange(this, getConfigFile()); } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to save "+getConfigFile(),e); + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to save " + getConfigFile(), e); } } @@ -153,7 +153,7 @@ public void loadAllBuilds() throws IOException{ putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); - addBuildInformation(information , build); + addBuildInformation(information, build); if(information.getSize()==0l){ information.setSize(buildOldDiskUsage); } @@ -190,7 +190,7 @@ public synchronized void load(){ buildDiskUsage = informations; } } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load "+file, e); + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load " + file, e); } // if(buildDiskUsage==null){ // //seems like it needs load old data @@ -214,7 +214,7 @@ public void loadOldData(){ AbstractBuild build = (AbstractBuild) run; BuildDiskUsageAction usage = run.getAction(BuildDiskUsageAction.class); DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); - addBuildInformation(information , build); + addBuildInformation(information, build); if(usage!=null){ information.setSize(usage.buildDiskUsage); run.getAllActions().remove(usage); diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index d909985d..4b288f15 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -291,7 +291,7 @@ public Graph getGraph() throws IOException { ArrayList builds = new ArrayList(); builds.addAll(property.getDiskUsageOfBuilds()); //do it in reverse order - for (int i=builds.size()-1; i>=0; i--) { + for(int i = builds.size() - 1; i >= 0; i--) { DiskUsageBuildInformation build = builds.get(i); Long diskUsage = property.getDiskUsageOfBuild(build.getId()); usages.add(new Object[]{build.getNumber(), getJobRootDirDiskUsage(), diskUsage, getAllSlaveWorkspaces(), getAllCustomOrNonSlaveWorkspaces()}); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index d826396e..5377cbcf 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -53,10 +53,10 @@ public void testGetAllDiskUsage() throws Exception{ Long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()){ AbstractBuild configurationBuild = c.getBuildByNumber(1); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count*size1); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count*size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count*size2); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count*size2; count++; } @@ -98,7 +98,7 @@ public void getBuildUsageStringMatrixProject() throws Exception{ break; } } - count ++; + count++; String size = (kiloBytes*count/1024) + " KB"; assertEquals("String representation of build disk usage which has " + size + " is wrong.", size, action.getBuildUsageString()); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index e1c1d5f5..9f031937 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -117,7 +117,7 @@ public void testExecuteMatrixProject() throws IOException, InterruptedException{ MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); AbstractBuild matrixBuild = project.getBuildByNumber(1); - Long matrixProjectBuildSize = getSize(readFileList(new File(matrixBuild.getRootDir(),"fileList"))) + matrixBuild.getRootDir().length(); + Long matrixProjectBuildSize = getSize(readFileList(new File(matrixBuild.getRootDir(), "fileList"))) + matrixBuild.getRootDir().length(); for(AbstractBuild build: project2.getBuilds()){ File file = new File(build.getRootDir(),"fileList"); buildSizesProject2.put(build, getSize(readFileList(file)) + build.getRootDir().length()); @@ -224,7 +224,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); assertEquals("Disk usage for excluded project should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(exludedJob.getLastBuild()).getAllDiskUsage(), 0); - assertTrue("Disk usage for excluded project should not be counted.", DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage()>0); + assertTrue("Disk usage for excluded project should not be counted.", DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage() > 0); excludes.clear(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index ab121694..5ff45e39 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -50,7 +50,7 @@ public void testOnCompleted() throws Exception{ j.buildAndAssertSuccess(project); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Build information is cached.", property.getDiskUsageBuildInformation(1)); - assertTrue("Build disk usage should be counted.", property.getDiskUsageOfBuild(1)>0); - assertTrue("Workspace of build should be counted.", property.getAllWorkspaceSize()>0); + assertTrue("Build disk usage should be counted.", property.getDiskUsageOfBuild(1) > 0); + assertTrue("Workspace of build should be counted.", property.getAllWorkspaceSize() > 0); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 48e9ee59..3460e3df 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -47,9 +47,9 @@ public void testRefreshGlobalInformation() throws IOException{ project.addProperty(property); } property.setDiskUsageWithoutBuilds(jobUsage); - property.putSlaveWorkspaceSize(j.jenkins, j.jenkins.getWorkspaceFor((TopLevelItem)project).getRemote(), workspaceUsage); + property.putSlaveWorkspaceSize(j.jenkins, j.jenkins.getWorkspaceFor((TopLevelItem) project).getRemote(), workspaceUsage); plugin.refreshGlobalInformation(); - assertEquals("Global build diskUsage should be refreshed.", sizeofBuild1 + sizeofBuild2 +sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0); + assertEquals("Global build diskUsage should be refreshed.", sizeofBuild1 + sizeofBuild2 + sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0); assertEquals("Global job diskUsage should be refreshed.", jobUsage, plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), 0); assertEquals("Global workspace diskUsage should be refreshed.", workspaceUsage, plugin.getCashedGlobalWorkspacesDiskUsage(), 0); @@ -60,7 +60,7 @@ public void testRefreshGlobalInformation() throws IOException{ public void testNotBreakLazyLoading() throws IOException{ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This tests does not sense if there are loaded all builds.",8>loadedBuilds); + assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); j.jenkins.getPlugin(DiskUsagePlugin.class).refreshGlobalInformation(); assertEquals("Size of builds should be loaded.", 47000, j.jenkins.getPlugin(DiskUsagePlugin.class).getCashedGlobalBuildsDiskUsage(), 0); assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index f598898d..d563905d 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -75,7 +75,7 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception{ for(MatrixConfiguration c: matrixProject.getItems()){ DiskUsageProperty configurationProperty = new DiskUsageProperty(); c.addProperty(configurationProperty); - configurationProperty.setDiskUsageWithoutBuilds(count*size1); + configurationProperty.setDiskUsageWithoutBuilds(count * size1); matrixProjectTotalSize += count*size1; //matrixProjectTotalSize += c.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); count++; @@ -117,8 +117,8 @@ public void testCheckWorkspaces() throws Exception{ public void getWorkspaceSizeTest() throws Exception{ RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(),"workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(),"workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); project.setAssignedLabel(slave1.getSelfLabel()); j.buildAndAssertSuccess(project); @@ -140,7 +140,7 @@ public void getWorkspaceSizeTest() throws Exception{ slaveInfo.put(path, workspaceSize); } } - assertEquals("DiskUsage workspaces which is configured as slave workspace is wrong.", workspaceSize*2, prop.getWorkspaceSize(true), 0); + assertEquals("DiskUsage workspaces which is configured as slave workspace is wrong.", workspaceSize * 2, prop.getWorkspaceSize(true), 0); assertEquals("DiskUsage workspaces which is not configured as slave workspace is wrong.", workspaceSize, prop.getWorkspaceSize(false), 0); } @@ -156,7 +156,7 @@ public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception{ FilePath path = j.jenkins.getWorkspaceFor(project); path.mkdirs(); property.putSlaveWorkspaceSize(j.jenkins, path.getRemote(), 10495l); - property.putSlaveWorkspaceSize(slave1,slave1.getRemoteFS(),5670l); + property.putSlaveWorkspaceSize(slave1, slave1.getRemoteFS(), 5670l); property.putSlaveWorkspaceSize(slave2, slave2.getRemoteFS(), 7987l); j.jenkins.removeNode(slave2); property.checkWorkspaces(); @@ -197,7 +197,7 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep } else { project.getBuildersList().add(new Shell("echo hello > log")); } - Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(),"SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(), "SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave slave1 = j.createOnlineSlave(); Slave slave2= j.createOnlineSlave(); File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName()+ "/log"); @@ -289,7 +289,7 @@ public void testGetDiskUsageOfBuilds(){ int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); for(DiskUsageBuildInformation information : property.getDiskUsageOfBuilds()){ - assertEquals("Disk usage of build has loaded wrong size.", information.getNumber()*1000, information.getSize(), 0); + assertEquals("Disk usage of build has loaded wrong size.", information.getNumber() * 1000, information.getSize(), 0); } assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); } @@ -336,7 +336,7 @@ public void testCheckWorkspacesBuildsWithoutLoadingBuilds() throws IOException, AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - FilePath f = j.jenkins.getWorkspaceFor((TopLevelItem)project); + FilePath f = j.jenkins.getWorkspaceFor((TopLevelItem) project); property.checkWorkspaces(); assertEquals("Workspace should have size 4096", 4096, property.getAllWorkspaceSize(), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); @@ -348,7 +348,7 @@ public void testCheckWorkspacesBuildsWithoutLoadingBuilds() throws IOException, public void testCheckWorkspacesWithLoadingBuilds() throws IOException { File file = new File(j.jenkins.getRootDir(),"jobs/project2/builds/1/build.xml"); XmlFile f = new XmlFile(new XStream2(), file); - String newBuildXml = f.asString().replace("${JENKINS_HOME}",j.jenkins.getRootDir().getAbsolutePath()); + String newBuildXml = f.asString().replace("${JENKINS_HOME}", j.jenkins.getRootDir().getAbsolutePath()); PrintStream st = new PrintStream(file); st.print(newBuildXml); AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); @@ -391,10 +391,10 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ Long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()){ AbstractBuild configurationBuild = c.getBuildByNumber(1); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count*size1); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count*size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count*size2); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count*size2; count++; } @@ -411,7 +411,7 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ public void testDoNotBreakLazyLoading(){ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This tests does not sense if there are loaded all builds.",8>loadedBuilds); + assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertEquals("Size of builds should be loaded.", 1000, property.getAllDiskUsageOfBuild(8), 0); assertEquals("Size of builds should be loaded.", 7000, property.getAllDiskUsageOfBuild(4), 0); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 4fd904df..16908322 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -108,8 +108,8 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception{ //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(),"workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(),"workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project1 = j.createFreeStyleProject("project1"); FreeStyleProject project2 = j.createFreeStyleProject("project2"); project1.setAssignedNode(slave1); @@ -139,7 +139,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); j.jenkins.setNumExecutors(0); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(),"workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); @@ -147,7 +147,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(),"workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); ArrayList slaves = new ArrayList(); slaves.add("slave2"); LabelAxis axis2 = new LabelAxis("label",slaves); @@ -158,9 +158,9 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis1").length(); - Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2").length(); - Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3").length(); + Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); for(MatrixConfiguration c: project1.getItems()){ DiskUsageUtil.calculateWorkspaceDiskUsage(c); } @@ -187,9 +187,9 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2", "fileList"); fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2", "fileList"); fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2", "fileList"); - sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2").length(); - sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2").length(); - sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2").length(); + sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); + sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); + sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); @@ -214,23 +214,23 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); plugin.getConfiguration().setCheckWorkspaceOnSlave(true); j.jenkins.setNumExecutors(0); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(),"workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = j.jenkins.createProject(MatrixProject.class,"project1"); + MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(),"workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); File fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2", "fileList"); File fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2", "fileList"); File fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2", "fileList"); - Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2").length(); - Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2").length(); - Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2").length(); + Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); + Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); + Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave2.getWorkspaceFor(project1).length() + sizeAxis1 + sizeAxis2 + sizeAxis3; DiskUsageUtil.calculateWorkspaceDiskUsage(project1); @@ -243,8 +243,8 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception{ RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(),"workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(),"workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project1 = j.createFreeStyleProject("project1"); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); @@ -254,9 +254,9 @@ public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesN prop = new DiskUsageProperty(); project1.addProperty(prop); } - prop.putSlaveWorkspaceSize(slave2, slave2.getWorkspaceFor((TopLevelItem)project1).getRemote(), 54356l); + prop.putSlaveWorkspaceSize(slave2, slave2.getWorkspaceFor((TopLevelItem) project1).getRemote(), 54356l); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - assertFalse("Slave slave2 should be removed from disk usage, because a workspace for project1 does not exist on this slave.",prop.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); + assertFalse("Slave slave2 should be removed from disk usage, because a workspace for project1 does not exist on this slave.", prop.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); assertTrue("Disk usage should contains slave1, there is a workspace for project1.", prop.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); } @@ -279,7 +279,7 @@ public void testParseExcludedJobsFromString() throws Exception{ excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); assertFalse("Excluded jobs should not contains jobs which does not exists.", excludedJobs.contains("Project5")); excluded = "Project with space, "; - assertTrue("Excluded jobs should be parsed correctly even if there additional separator", excludedJobs.contains(projectWithSpace.getName()) && excludedJobs.size()==1); + assertTrue("Excluded jobs should be parsed correctly even if there additional separator", excludedJobs.contains(projectWithSpace.getName()) && excludedJobs.size() == 1); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 9c348df8..0f962386 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -65,10 +65,10 @@ public void testGetBuildsDiskUsage() throws Exception{ Long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()){ AbstractBuild configurationBuild = c.getBuildByNumber(1); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count*size1); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count*size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count*size2); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count*size2; count++; } @@ -107,10 +107,10 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception{ Long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()){ AbstractBuild configurationBuild = c.getBuildByNumber(1); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count*size1); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count*size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); - DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count*size2); + DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count*size2; count++; } @@ -175,7 +175,7 @@ public void testNotToBreakLazyLoading() throws IOException{ int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); project.getAction(ProjectDiskUsageAction.class).getGraph(); - assertTrue("Creation of graph should not cause loading of builds.", project._getRuns().getLoadedBuilds().size() <= loadedBuilds ); + assertTrue("Creation of graph should not cause loading of builds.", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java index d203afe2..af109779 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java @@ -42,7 +42,7 @@ public void testAllInfoLoaded() throws IOException{ @LocalData public void testFirstLoad() throws IOException{ AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - Set informations = ((DiskUsageProperty)project.getProperty(DiskUsageProperty.class)).getDiskUsage().getBuildDiskUsage(false); + Set informations = ((DiskUsageProperty) project.getProperty(DiskUsageProperty.class)).getDiskUsage().getBuildDiskUsage(false); assertEquals("Set of DisUsageBuildInformation should not contain information about builds because they are not loaded.", 0, informations.size()); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index c7758089..94cf1e7f 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -107,8 +107,8 @@ public void testExecute() throws IOException, InterruptedException, Exception{ //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); - Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(),"workspace2").getPath()); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); FreeStyleProject project1 = j.createFreeStyleProject("project1"); FreeStyleProject project2 = j.createFreeStyleProject("project2"); project1.setAssignedNode(slave1); @@ -141,22 +141,22 @@ public void testExecuteMatrixProject() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); j.getInstance().setNumExecutors(0); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); axes.add(axis1); - MatrixProject project1 = j.jenkins.createProject(MatrixProject.class,"project1"); + MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); - MatrixProject project2 = j.jenkins.createProject(MatrixProject.class,"project2"); + MatrixProject project2 = j.jenkins.createProject(MatrixProject.class, "project2"); AxisList axes2 = new AxisList(); TextAxis axis2 = new TextAxis("axis","axis1 axis2"); axes2.add(axis2); project2.setAxes(axes2); project2.setAssignedNode(slave1); j.buildAndAssertSuccess(project2); - Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(),"workspace2").getPath()); + Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); slave1.toComputer().setTemporarilyOffline(true, null); project1.setAssignedNode(slave2); j.buildAndAssertSuccess(project1); @@ -173,17 +173,17 @@ public void testExecuteMatrixProject() throws Exception { File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - Long sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis1").length(); - Long sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2").length(); - Long sizeAxis3 = getSize(readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3").length(); + Long sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + Long sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + Long sizeAxis3 = getSize(readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1", "fileList"); fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); size += getSize(readFileList(file)) + slave2.getWorkspaceFor(project1).length(); - sizeAxis1 += getSize(readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1").length(); - sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2").length(); - sizeAxis3 += getSize(readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3").length(); + sizeAxis1 += getSize(readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + sizeAxis3 += getSize(readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); @@ -194,8 +194,8 @@ public void testExecuteMatrixProject() throws Exception { fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis1", "fileList"); fileAxis2 = new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis2", "fileList"); size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length(); - sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis1").length(); - sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis2").length(); + sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); + sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); @@ -222,7 +222,7 @@ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throw FreeStyleProject project = j.getInstance().createProject(FreeStyleProject.class, "project1"); TestDiskUsageProperty prop = new TestDiskUsageProperty(); project.addProperty(prop); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath()); + Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); prop.putSlaveWorkspace(slave1, slave1.getWorkspaceFor(project).getRemote()); Thread t = new Thread(testCalculation.getThreadName()){ @@ -251,7 +251,7 @@ public void testDoNotBreakLazyLoading() throws Exception{ assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertTrue("WorkspaceCalculation should not cause loading of builds (only if the plugin is used for first time).", project._getRuns().getLoadedBuilds().size() <= loadedBuilds ); + assertTrue("WorkspaceCalculation should not cause loading of builds (only if the plugin is used for first time).", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); } @@ -271,7 +271,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ excludedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); includedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); } - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); excludedJob.setAssignedLabel(slave1.getSelfLabel()); includedJob.setAssignedLabel(slave1.getSelfLabel()); j.buildAndAssertSuccess(excludedJob); @@ -287,7 +287,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ @LocalData public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception{ FreeStyleProject job = j.getInstance().createProject(FreeStyleProject.class, "project1"); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(),"workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); + Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); job.setAssignedLabel(slave1.getSelfLabel()); j.buildAndAssertSuccess(job); j.buildAndAssertSuccess(job); @@ -297,7 +297,7 @@ public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception{ WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces()); - assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces(),0); + assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces(), 0); } @TestExtension From 3e725e26cebd4d791c1e1867b3bcc02a31ed13ba Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 00:03:43 +0000 Subject: [PATCH 038/158] Clean code using openrewrite EqualsAvoidsNull recipe --- .../java/hudson/plugins/disk_usage/DiskUsageUtil.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 47fa0fec..e929d48e 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -149,7 +149,7 @@ public static void sendEmail(String subject, String message) throws MessagingExc } public static Long getSizeInBytes(String stringSize){ - if(stringSize==null || stringSize.equals("-")) + if(stringSize==null || "-".equals(stringSize)) return 0l; String[] values = stringSize.split(" "); int index = getIndex(values[1]); @@ -235,13 +235,13 @@ public static double getScale(long number) { public static int getIndex(String unit){ int index = 0; - if(unit.equals("KB")) + if("KB".equals(unit)) index = 1; - if(unit.equals("MB")) + if("MB".equals(unit)) index = 2; - if(unit.equals("GB")) + if("GB".equals(unit)) index = 3; - if(unit.equals("TB")) + if("TB".equals(unit)) index = 4; return index; } From 0bafe98dae194c811f8a1f76ede856fade655bb5 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 00:19:19 +0000 Subject: [PATCH 039/158] Clean code using openrewrite NeedBraces recipe --- .../disk_usage/BuildDiskUsageAction.java | 3 +- .../BuildDiskUsageCalculationThread.java | 5 +- .../disk_usage/DiskUsageBuildInformation.java | 3 +- .../disk_usage/DiskUsageCalculation.java | 12 ++-- .../disk_usage/DiskUsageItemListener.java | 8 ++- .../DiskUsageOvearallGraphGenerator.java | 18 ++++-- .../plugins/disk_usage/DiskUsagePlugin.java | 30 ++++++---- .../DiskUsageProjectActionFactory.java | 15 +++-- .../plugins/disk_usage/DiskUsageProperty.java | 36 +++++++---- .../plugins/disk_usage/DiskUsageRecord.java | 12 ++-- .../plugins/disk_usage/DiskUsageUtil.java | 59 ++++++++++++------- .../JobWithoutBuildsDiskUsageCalculation.java | 8 ++- .../plugins/disk_usage/ProjectDiskUsage.java | 12 ++-- .../disk_usage/ProjectDiskUsageAction.java | 16 +++-- .../WorkspaceDiskUsageCalculationThread.java | 8 ++- .../BuildDiskUsageCalculationThreadTest.java | 3 +- .../integration/DiskUsagePropertyTest.java | 3 +- .../integration/DiskUsageTestUtil.java | 3 +- .../JobDiskUsageCalculationThreadTest.java | 6 +- ...rkspaceDiskUsageCalculationThreadTest.java | 8 ++- 20 files changed, 174 insertions(+), 94 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index d6bf3775..d109c073 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -124,8 +124,9 @@ public Object readResolve() { if(node!=null && diskUsage.wsUsage!=null && diskUsage.wsUsage > 0){ DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); AbstractProject project = build.getProject().getRootProject(); - if(property!=null && (project instanceof TopLevelItem)) + if(property != null && (project instanceof TopLevelItem)) { property.putSlaveWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); + } } diskUsage=null; } diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index 0f471126..e1e4179d 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -108,8 +108,9 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution(){ DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationBuildsEnabled()) - return false; + if(!plugin.getConfiguration().isCalculationBuildsEnabled()) { + return false; + } return !isExecutingMoreThenOneTimes(); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index a2f7b93c..8dfbc727 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -54,8 +54,9 @@ public int getNumber(){ } public Long getSize(){ - if(size==null) + if(size == null) { return 0L; + } return size; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index cdf3c72b..35d83901 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -31,8 +31,9 @@ public DiskUsageCalculation(String name){ public boolean isExecuting() { for(Thread t: Thread.getAllStackTraces().keySet()){ - if(t.getName().equals(getThreadName())) + if(t.getName().equals(getThreadName())) { return t.isAlive() && !t.isInterrupted(); + } } return false; } @@ -41,8 +42,9 @@ public boolean isExecutingMoreThenOneTimes() { int count = 0; for(Thread t: Thread.getAllStackTraces().keySet()){ if(t.getName().equals(getThreadName())){ - if(t.isAlive() && !t.isInterrupted()) + if(t.isAlive() && !t.isInterrupted()) { count++; + } } } return count>1; @@ -57,8 +59,9 @@ public String getThreadName(){ public long scheduledLastInstanceExecutionTime() { try { CronTab tab = null; - if(getLastTask()==null || getLastTask().isCancelled()) //not scheduled + if(getLastTask() == null || getLastTask().isCancelled()) { //not scheduled return 0l; + } tab = getLastTask().getCronTab(); long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); if(time< new GregorianCalendar().getTimeInMillis()){ @@ -117,8 +120,9 @@ public long getRecurrencePeriod() { GregorianCalendar now = new GregorianCalendar(); Calendar nextExecution = tab.ceil(now.getTimeInMillis()); long period = nextExecution.getTimeInMillis() - now.getTimeInMillis(); - if(nextExecution.getTimeInMillis() - now.getTimeInMillis()<=60000) + if(nextExecution.getTimeInMillis() - now.getTimeInMillis() <= 60000) { period = period + 60000l; //add one minute to not shedule it during one minute one than once + } return period; } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java index c7782886..1f00864c 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java @@ -20,14 +20,16 @@ public class DiskUsageItemListener extends ItemListener{ @Override public void onDeleted(Item item) { - if(item instanceof AbstractProject) - DiskUsageProjectActionFactory.DESCRIPTOR.onDeleteJob((AbstractProject) item); + if(item instanceof AbstractProject) { + DiskUsageProjectActionFactory.DESCRIPTOR.onDeleteJob((AbstractProject) item); + } } @Override public void onRenamed(Item item, String oldName, String newName) { - if(item instanceof AbstractProject) + if(item instanceof AbstractProject) { DiskUsageProjectActionFactory.DESCRIPTOR.onRenameJob(oldName, newName); + } } @Override diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 5b36efe3..565b5ac8 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -57,38 +57,44 @@ public String toString(){ } public Long getNonSlaveWorkspacesUsage(){ - if(diskUsageNonSlaveWorkspaces==null) + if(diskUsageNonSlaveWorkspaces == null) { return 0l; + } return diskUsageNonSlaveWorkspaces; } public Long getSlaveWorkspacesUsage(){ - if(diskUsageNonSlaveWorkspaces==null) + if(diskUsageNonSlaveWorkspaces == null) { return getWorkspacesDiskUsage(); + } return getWorkspacesDiskUsage() - diskUsageNonSlaveWorkspaces; } public Long getBuildsDiskUsage(){ - if(buildUsage==null) + if(buildUsage == null) { return 0l; + } return buildUsage; } public Long getJobsDiskUsage(){ - if(jobsWithoutBuildsUsage==null) + if(jobsWithoutBuildsUsage == null) { return getBuildsDiskUsage(); + } return jobsWithoutBuildsUsage + getBuildsDiskUsage(); } public Long getAllSpace(){ - if(allSpace==null) + if(allSpace == null) { return 0l; + } return allSpace; } public Long getWorkspacesDiskUsage(){ - if(wsUsage==null) + if(wsUsage == null) { return 0l; + } return wsUsage; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 60c716a6..f37a6c0e 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -152,9 +152,13 @@ public int compare(AbstractProject o1, AbstractProject o2) { ProjectDiskUsageAction dua1 = getDiskUsage(o1); ProjectDiskUsageAction dua2 = getDiskUsage(o2); long result = dua2.getJobRootDirDiskUsage() + dua2.getAllDiskUsageWorkspace() - dua1.getJobRootDirDiskUsage() - dua1.getAllDiskUsageWorkspace(); - - if(result > 0) return 1; - if(result < 0) return -1; + + if(result > 0) { + return 1; + } + if(result < 0) { + return -1; + } return 0; } }; @@ -228,44 +232,50 @@ public Graph getOverallGraph(){ public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); - if(getConfiguration().isCalculationBuildsEnabled() && !getBuildsDiskUsageThread().isExecuting()) + if(getConfiguration().isCalculationBuildsEnabled() && !getBuildsDiskUsageThread().isExecuting()) { getBuildsDiskUsageThread().doAperiodicRun(); + } res.forwardToPreviousPage(req); } public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); - if(getConfiguration().isCalculationJobsEnabled() && !getJobsDiskUsageThread().isExecuting()) + if(getConfiguration().isCalculationJobsEnabled() && !getJobsDiskUsageThread().isExecuting()) { getJobsDiskUsageThread().doAperiodicRun(); + } res.forwardToPreviousPage(req); } public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); - if(getConfiguration().isCalculationWorkspaceEnabled() && !getWorkspaceDiskUsageThread().isExecuting()) + if(getConfiguration().isCalculationWorkspaceEnabled() && !getWorkspaceDiskUsageThread().isExecuting()) { getWorkspaceDiskUsageThread().doAperiodicRun(); + } res.forwardToPreviousPage(req); } public String getCountIntervalForBuilds(){ long nextExecution = getBuildsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution<=0) //not scheduled - nextExecution = getBuildsDiskUsageThread().getRecurrencePeriod(); + if(nextExecution <= 0) { //not scheduled + nextExecution = getBuildsDiskUsageThread().getRecurrencePeriod(); + } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public String getCountIntervalForJobs(){ long nextExecution = getJobsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution<=0) //not scheduled + if(nextExecution <= 0) { //not scheduled nextExecution = getJobsDiskUsageThread().getRecurrencePeriod(); + } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public String getCountIntervalForWorkspaces(){ long nextExecution = getWorkspaceDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution<=0) //not scheduled + if(nextExecution <= 0) { //not scheduled nextExecution = getWorkspaceDiskUsageThread().getRecurrencePeriod(); + } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 888bbe66..8d3c6ac7 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -254,14 +254,16 @@ public void disableWorkspacesDiskUsageCalculation(){ } public String getUnit(String unit){ - if(unit==null) + if(unit == null) { return null; + } return unit.split(" ")[1]; } public String getValue(String size){ - if(size==null) + if(size == null) { return null; + } return size.split(" ")[0]; } @@ -355,8 +357,9 @@ private void configureBuildsCalculation(JSONObject form){ calculationBuilds = form.containsKey("calculationBuilds"); countIntervalBuilds = calculationBuilds? form.getJSONObject("calculationBuilds").getString("countIntervalBuilds") : "0 */6 * * *"; BuildDiskUsageCalculationThread buildCalculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); - if(!oldCountIntervalBuilds.equals(countIntervalBuilds) || oldCalculationBuilds!=calculationBuilds) + if(!oldCountIntervalBuilds.equals(countIntervalBuilds) || oldCalculationBuilds != calculationBuilds) { buildCalculation.reschedule(); + } } private void configureJobsCalculation(JSONObject form){ @@ -365,8 +368,9 @@ private void configureJobsCalculation(JSONObject form){ calculationJobs = form.containsKey("calculationJobs"); countIntervalJobs = calculationJobs? form.getJSONObject("calculationJobs").getString("countIntervalJobs") : "0 */6 * * *"; JobWithoutBuildsDiskUsageCalculation jobCalculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); - if(!oldcountIntervalJobs.equals(countIntervalJobs) || oldCalculationJobs!=calculationJobs) + if(!oldcountIntervalJobs.equals(countIntervalJobs) || oldCalculationJobs != calculationJobs) { jobCalculation.reschedule(); + } } private void configureWorkspacesCalculation(JSONObject form){ @@ -375,8 +379,9 @@ private void configureWorkspacesCalculation(JSONObject form){ calculationWorkspace = form.containsKey("calculationWorkspace"); countIntervalWorkspace = calculationWorkspace? form.getJSONObject("calculationWorkspace").getString("countIntervalWorkspace") : "0 */6 * * *"; WorkspaceDiskUsageCalculationThread workspaceCalculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); - if(!oldCountIntervalWorkspace.equals(countIntervalWorkspace) || oldCalculationWorkspace!=calculationWorkspace) + if(!oldCountIntervalWorkspace.equals(countIntervalWorkspace) || oldCalculationWorkspace != calculationWorkspace) { workspaceCalculation.reschedule(); + } } public int getTimeoutWorkspace() { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 5d73f42f..18063204 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -162,8 +162,9 @@ public void putSlaveWorkspace(Node node, String path){ if(workspacesInfo==null){ workspacesInfo = new ConcurrentHashMap(); } - if(!workspacesInfo.containsKey(path)) + if(!workspacesInfo.containsKey(path)) { workspacesInfo.put(path, 0l); + } getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); } @@ -178,8 +179,9 @@ public Map> getSlaveWorkspaceUsage(){ public void putSlaveWorkspaceSize(Node node, String path, Long size){ Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); - if(workspacesInfo==null) - workspacesInfo = new ConcurrentHashMap(); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); + } workspacesInfo.put(path, size); getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); @@ -196,8 +198,9 @@ public Long getWorkspaceSize(Boolean containdedInWorkspace){ if(node instanceof Slave){ workspacePath = ((Slave) node).getRemoteFS(); } - if(workspacePath==null) + if(workspacePath == null) { continue; + } Map paths = getSlaveWorkspaceUsage().get(nodeName); for(String path: paths.keySet()){ if(containdedInWorkspace.equals(path.startsWith(workspacePath))){ @@ -214,16 +217,18 @@ private void checkAllBuilds(){ if(!build.isBuilding()){ Node node = build.getBuiltOn(); FilePath path = build.getWorkspace(); - if(path==null) + if(path == null) { continue; + } Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo==null){ workspacesInfo = new ConcurrentHashMap(); workspacesInfo.put(path.getRemote(), 0L); } else{ - if(!workspacesInfo.keySet().contains(path.getRemote())) + if(!workspacesInfo.keySet().contains(path.getRemote())) { workspacesInfo.put(path.getRemote(), 0L); + } } getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); } @@ -238,16 +243,18 @@ private void checkLoadedBuilds(){ if(!build.isBuilding()){ Node node = build.getBuiltOn(); FilePath path = build.getWorkspace(); - if(path==null) + if(path == null) { continue; + } Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo==null){ workspacesInfo = new ConcurrentHashMap(); workspacesInfo.put(path.getRemote(), 0L); } else{ - if(!workspacesInfo.keySet().contains(path.getRemote())) + if(!workspacesInfo.keySet().contains(path.getRemote())) { workspacesInfo.put(path.getRemote(), 0L); + } } getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); } @@ -288,8 +295,9 @@ public void checkWorkspaces(boolean force) { while(iterator.hasNext()){ String nodeName = iterator.next(); Node node = Jenkins.getInstance().getNode(nodeName); - if(node==null && nodeName.isEmpty()) + if(node == null && nodeName.isEmpty()) { node = Jenkins.getInstance(); + } //delete name of slaves which do not exist if(node ==null) {//Jenkins master has empty name iterator.remove(); @@ -329,9 +337,10 @@ public Long getAllNonSlaveOrCustomWorkspaceSize(){ } else{ node = Jenkins.getInstance().getNode(nodeName); - } - if(node==null) //slave does not exist + } + if(node == null) { //slave does not exist continue; + } Map paths = getSlaveWorkspaceUsage().get(nodeName); for(String path: paths.keySet()){ TopLevelItem item = null; @@ -411,8 +420,9 @@ public Long getDiskUsageWithoutBuilds(){ } public Long getAllDiskUsageWithoutBuilds(){ - if(diskUsage.diskUsageWithoutBuilds==null) - diskUsage.diskUsageWithoutBuilds=0l; + if(diskUsage.diskUsageWithoutBuilds == null) { + diskUsage.diskUsageWithoutBuilds = 0l; + } Long usage = diskUsage.diskUsageWithoutBuilds; if(owner instanceof ItemGroup){ ItemGroup group = (ItemGroup) owner; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index 095ae242..bda736ff 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -29,8 +29,9 @@ public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long disk } public Long getBuildsDiskUsage(){ - if(diskUsageBuilds==null) + if(diskUsageBuilds == null) { return 0l; + } return diskUsageBuilds; } @@ -43,20 +44,23 @@ public Long getSlaveWorkspacesUsage(){ } public Long getJobsDiskUsage(){ - if(diskUsageJobsWithoutBuilds==null) + if(diskUsageJobsWithoutBuilds == null) { return getBuildsDiskUsage(); + } return diskUsageJobsWithoutBuilds + getBuildsDiskUsage(); } public Long getAllSpace(){ - if(allSpace==null) + if(allSpace == null) { return 0l; + } return allSpace; } public Long getWorkspacesDiskUsage(){ - if(diskUsageWorkspaces==null) + if(diskUsageWorkspaces == null) { return 0l; + } return diskUsageWorkspaces; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index e929d48e..903a0cdf 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -94,8 +94,9 @@ protected static void loadData(DiskUsageProperty property, boolean loadAllBuilds } public static Date getDate(String timeCount, String timeUnit){ - if(timeUnit==null || !timeUnit.matches("\\d+") || !timeCount.matches("\\d+")) - return null; + if(timeUnit == null || !timeUnit.matches("\\d+") || !timeCount.matches("\\d+")) { + return null; + } int unit = Integer.decode(timeUnit); int count = Integer.decode(timeCount); return getDate(unit, count); @@ -149,8 +150,9 @@ public static void sendEmail(String subject, String message) throws MessagingExc } public static Long getSizeInBytes(String stringSize){ - if(stringSize==null || "-".equals(stringSize)) + if(stringSize == null || "-".equals(stringSize)) { return 0l; + } String[] values = stringSize.split(" "); int index = getIndex(values[1]); Long value = Long.decode(values[0]); @@ -208,8 +210,9 @@ public static List parseExcludedJobsFromString(String jobs){ for(String name: jobNames){ name = name.trim(); Item item = Jenkins.getInstance().getItem(name); - if(item!=null && item instanceof AbstractProject) + if(item != null && item instanceof AbstractProject) { list.add(name); + } } return list; } @@ -228,21 +231,26 @@ public static String getSizeString(Long size) { } public static double getScale(long number) { - if(number==0) + if(number == 0) { return 0; + } return Math.floor(Math.log(number) / Math.log(1024)); } public static int getIndex(String unit){ int index = 0; - if("KB".equals(unit)) + if("KB".equals(unit)) { index = 1; - if("MB".equals(unit)) + } + if("MB".equals(unit)) { index = 2; - if("GB".equals(unit)) - index = 3; - if("TB".equals(unit)) + } + if("GB".equals(unit)) { + index = 3; + } + if("TB".equals(unit)) { index = 4; + } return index; } @@ -336,25 +344,32 @@ public static boolean isSymlink(File f) throws IOException{ public static Long getFileSize(File f, List exceedFiles) throws IOException { long size = 0; - if(!f.exists()) - return size; + if(!f.exists()) { + return size; + } if (f.isDirectory() && !isSymlink(f)) { File[] fileList = f.listFiles(); - if (fileList != null) for (File child : fileList) { - if(exceedFiles.contains(child)) - continue; //do not count exceeded files - if (!isSymlink(child)) size += getFileSize(child, exceedFiles); + if(fileList != null) { + for(File child: fileList) { + if(exceedFiles.contains(child)) { + continue; + } //do not count exceeded files + if(!isSymlink(child)) { + size += getFileSize(child, exceedFiles); + } + } } else { - LOGGER.info("Failed to list files in " + f.getPath() + " - ignoring"); - } + LOGGER.info("Failed to list files in " + f.getPath() + " - ignoring"); + } } return size + f.length(); } public static void calculateDiskUsageForProject(AbstractProject project) throws IOException{ - if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) + if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; + } DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); List exceededFiles = new ArrayList(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -412,8 +427,9 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws // } public static void calculateDiskUsageForBuild(String buildId, AbstractProject project) throws IOException { - if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) + if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; + } DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); //Build disk usage has to be always recalculated to be kept up-to-date //- artifacts might be kept only for the last build and users sometimes delete files manually as well. @@ -483,8 +499,9 @@ public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayL } public static void calculateWorkspaceDiskUsage(AbstractProject project) throws IOException, InterruptedException { - if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) + if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; + } DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property==null){ addProperty(project); diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 4b8ddd6b..21d37f2f 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -46,8 +46,9 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept if (item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; //do not count building project - if(project.isBuilding()) + if(project.isBuilding()) { continue; + } try{ DiskUsageUtil.calculateDiskUsageForProject(project); } catch (Exception ex) { @@ -99,8 +100,9 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution(){ DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationJobsEnabled()) - return false; + if(!plugin.getConfiguration().isCalculationJobsEnabled()) { + return false; + } return !isExecutingMoreThenOneTimes(); } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index cda6601a..abd08fe8 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -74,7 +74,9 @@ public Set getBuildDiskUsage(boolean needAll){ } public synchronized void save() { - if(BulkChange.contains(this)) return; + if(BulkChange.contains(this)) { + return; + } try { getConfigFile().write(this); SaveableListener.fireOnChange(this, getConfigFile()); @@ -103,8 +105,9 @@ private int numberOfBuildFolders() throws IOException{ public void putSlaveWorkspaceSize(Node node, String path, Long size){ Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); - if(workspacesInfo==null) - workspacesInfo = new ConcurrentHashMap(); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); + } //worksace with 0 are only initiative (are not counted yet) or does not exists //no nexist workspaces are removed in method checkWorkspaces in class DiskUsageProperty if(workspacesInfo.get(path)==null || size>0l ){ @@ -248,8 +251,9 @@ private void removeDeletedBuilds(){ while(iterator.hasNext()){ DiskUsageBuildInformation information = iterator.next(); File buildDir = new File(Jenkins.getInstance().getBuildDirFor(job), information.getId()); - if(!buildDir.exists()) + if(!buildDir.exists()) { buildDiskUsage.remove(information); + } } } } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 4b288f15..3f5fc661 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -163,10 +163,12 @@ private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date old Set informations = property.getDiskUsageOfBuilds(); for(DiskUsageBuildInformation information: informations){ Date date = new Date(information.getTimestamp()); - if(older!=null && !date.before(older)) + if(older != null && !date.before(older)) { continue; - if(yonger!=null && !date.after(yonger)) + } + if(yonger != null && !date.after(yonger)) { continue; + } Long size = information.getSize(); buildsDiskUsage += size; Collection loadedBuilds = (Collection) p._getRuns().getLoadedBuilds().values(); @@ -227,10 +229,12 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx Set informations = property.getDiskUsageOfBuilds(); for(DiskUsageBuildInformation information: informations){ Date date = new Date(information.getTimestamp()); - if(older!=null && !date.before(older)) - continue; - if(yonger!=null && !date.after(yonger)) - continue; + if(older != null && !date.before(older)) { + continue; + } + if(yonger != null && !date.after(yonger)) { + continue; + } Long size = information.getSize(); buildsDiskUsage += size; Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 3d72485c..2079a752 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -44,8 +44,9 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept if (item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; //do not count workspace for running project - if(project.isBuilding()) + if(project.isBuilding()) { continue; + } try{ DiskUsageUtil.calculateWorkspaceDiskUsage(project); } catch (Exception ex) { @@ -95,8 +96,9 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution(){ DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationWorkspaceEnabled()) - return false; + if(!plugin.getConfiguration().isCalculationWorkspaceEnabled()) { + return false; + } return !isExecutingMoreThenOneTimes(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index 9f031937..9b43e607 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -44,8 +44,9 @@ private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) th //wait until thread ends for(Thread t : Thread.getAllStackTraces().keySet()){ if(calculation.name.equals(t.getName())){ - while(thread.isAlive()) + while(thread.isAlive()) { Thread.sleep(100); + } break; } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index d563905d..a58a7b60 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -580,8 +580,9 @@ public Exception getException(){ class CurrentWorkspacePath extends JenkinsRecipe.Runner{ private String paths; public void decorateHome(JenkinsRule rule, File home){ - if(paths.isEmpty()) + if(paths.isEmpty()) { return; + } for(String path : paths.split(",")){ path = path.trim(); try { diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index b328ab95..a68b4272 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -64,8 +64,9 @@ protected static Slave createSlave(String name, String remoteFS, Jenkins jenkins protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build){ for(Action a : build.getAllActions()){ - if(a instanceof BuildDiskUsageAction) + if(a instanceof BuildDiskUsageAction) { return (BuildDiskUsageAction) a; + } } return null; } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 80328f48..f6590a73 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -117,8 +117,9 @@ public void testMatrixProject() throws IOException, InterruptedException{ matrixConfigurationsSize.put(config.getDisplayName(), size + diskUsageXML); } JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); - if(calculation.isExecuting()) + if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); + } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); assertEquals("Project project has wrong job size.", projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); @@ -162,8 +163,9 @@ public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ @Test public void testDoNotCalculateExcludedJobs() throws Exception{ JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); - if(calculation.isExecuting()) + if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); + } FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); List excludes = new ArrayList(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index 94cf1e7f..27d72263 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -62,8 +62,9 @@ private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation //wait until thread ends for(Thread t : Thread.getAllStackTraces().keySet()){ if(calculation.name.equals(t.getName())){ - while(thread.isAlive()) + while(thread.isAlive()) { Thread.sleep(100); + } break; } } @@ -312,8 +313,9 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size){ Logger.getLogger(WorkspaceDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); - if(workspacesInfo==null) - workspacesInfo = new ConcurrentHashMap(); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); + } workspacesInfo.put(path, size); getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); From 76a00e261693195b0eb892107299e31693de7b35 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 00:46:23 +0000 Subject: [PATCH 040/158] Clean code using openrewrite AutoFormat recipe --- .../disk_usage/BuildDiskUsageAction.java | 102 +-- .../BuildDiskUsageCalculationThread.java | 88 +-- .../hudson/plugins/disk_usage/DiskUsage.java | 13 +- .../DiskUsageBuildActionFactory.java | 4 +- .../disk_usage/DiskUsageBuildInformation.java | 44 +- .../disk_usage/DiskUsageBuildListener.java | 42 +- .../disk_usage/DiskUsageCalculation.java | 84 +-- .../plugins/disk_usage/DiskUsageGraph.java | 128 ++-- .../disk_usage/DiskUsageItemListener.java | 28 +- .../disk_usage/DiskUsageManagement.java | 51 +- .../DiskUsageOvearallGraphGenerator.java | 166 ++--- .../plugins/disk_usage/DiskUsagePlugin.java | 162 ++--- .../DiskUsageProjectActionFactory.java | 618 +++++++++--------- .../plugins/disk_usage/DiskUsageProperty.java | 528 +++++++-------- .../plugins/disk_usage/DiskUsageRecord.java | 46 +- .../plugins/disk_usage/DiskUsageUtil.java | 424 ++++++------ .../DiskUsageWorkspaceListener.java | 10 +- .../JobWithoutBuildsDiskUsageCalculation.java | 48 +- .../disk_usage/ProjectConfigListener.java | 4 +- .../plugins/disk_usage/ProjectDiskUsage.java | 194 +++--- .../disk_usage/ProjectDiskUsageAction.java | 212 +++--- .../WorkspaceDiskUsageCalculationThread.java | 56 +- .../DiskUsagePostBuildCalculation.java | 25 +- .../disk_usage/DiskUsageCalculationTest.java | 73 +-- .../plugins/disk_usage/DiskUsageUtilTest.java | 39 +- .../disk_usage/TestDiskUsageCalculation.java | 45 +- .../integration/BuildDiskUsageActionTest.java | 44 +- .../BuildDiskUsageCalculationThreadTest.java | 166 ++--- .../DiskUsageBuildListenerTest.java | 12 +- .../integration/DiskUsagePluginTest.java | 42 +- .../integration/DiskUsagePropertyTest.java | 308 ++++----- .../integration/DiskUsageTestUtil.java | 48 +- .../integration/DiskUsageUtilTest.java | 106 +-- .../JobDiskUsageCalculationThreadTest.java | 68 +- .../ProjectDiskUsageActionTest.java | 100 +-- .../integration/ProjectDiskUsageTest.java | 22 +- ...rkspaceDiskUsageCalculationThreadTest.java | 110 ++-- .../DiskUsagePostBuildCalculationTest.java | 20 +- 38 files changed, 2140 insertions(+), 2140 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index d109c073..26f8a72e 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -30,12 +30,12 @@ public class BuildDiskUsageAction implements ProminentProjectAction, BuildBadgeA AbstractBuild build; @Deprecated DiskUsage diskUsage; - + public BuildDiskUsageAction(AbstractBuild build) { this.build = build; - } + } - public String getIconFileName() { + public String getIconFileName() { return null; } @@ -46,89 +46,89 @@ public String getDisplayName() { public String getUrlName() { return Messages.UrlName(); } - - public void setDiskUsage(Long size) throws IOException{ + + public void setDiskUsage(Long size) throws IOException { AbstractProject project = build.getProject(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); - if(information!=null){ + if(information != null) { information.setSize(size); } - else{ + else { property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); } - property.saveDiskUsage(); + property.saveDiskUsage(); } - + /** * @return Disk usage of the build (included child builds) */ public Long getDiskUsage() { AbstractProject project = build.getProject(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } return property.getDiskUsageOfBuild(build.getId()); } - - public Long getAllDiskUsage(){ + + public Long getAllDiskUsage() { Long buildsDiskUsage = getDiskUsage(); AbstractProject project = build.getProject(); - if(project instanceof ItemGroup){ - buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) project); - } + if(project instanceof ItemGroup) { + buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) project); + } return buildsDiskUsage; } - - public String getBuildUsageString(){ + + public String getBuildUsageString() { return DiskUsageUtil.getSizeString(getAllDiskUsage()); } - private Long getBuildsDiskUsageAllSubItems(ItemGroup group){ + private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { Long buildsDiskUsage = 0l; - for(Object item: group.getItems()){ - if(item instanceof ItemGroup){ + for(Object item: group.getItems()) { + if(item instanceof ItemGroup) { buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) item); } - else{ - if(item instanceof AbstractProject){ + else { + if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } Set informations = property.getDiskUsageOfBuilds(); - for(DiskUsageBuildInformation information : informations){ - if(information.getNumber() == build.getNumber()){ + for(DiskUsageBuildInformation information: informations) { + if(information.getNumber() == build.getNumber()) { buildsDiskUsage += information.getSize(); } - } + } } } } return buildsDiskUsage; } - + public Object readResolve() { //for keeping backward compatibility - if(diskUsage!=null){ + if(diskUsage != null) { buildDiskUsage = diskUsage.buildUsage; Node node = build.getBuiltOn(); - if(node!=null && diskUsage.wsUsage!=null && diskUsage.wsUsage > 0){ + if(node != null && diskUsage.wsUsage != null && diskUsage.wsUsage > 0) { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); AbstractProject project = build.getProject().getRootProject(); if(property != null && (project instanceof TopLevelItem)) { property.putSlaveWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); } } - diskUsage=null; + diskUsage = null; } return this; } @@ -142,32 +142,32 @@ public void onAttached(Run r) { public void onLoad(Run r) { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); long size = 0L; - if(property==null){ + if(property == null) { return; } //backward compatibility BuildDiskUsageAction action = null; - for(Action a : build.getActions()){ - if(a instanceof BuildDiskUsageAction){ - action = (BuildDiskUsageAction) a; - if(action.buildDiskUsage != null){ - size=action.buildDiskUsage; - } - } - } - if(action!=null){ - //remove old action, now it is added by transition action factory - build.getActions().remove(action); - try { - build.save(); - } catch (IOException ex) { - Logger.getLogger(BuildDiskUsageAction.class.getName()).log(Level.SEVERE, null, ex); + for(Action a: build.getActions()) { + if(a instanceof BuildDiskUsageAction) { + action = (BuildDiskUsageAction) a; + if(action.buildDiskUsage != null) { + size = action.buildDiskUsage; } } - //Transient actions can be created even during deletion of job - if(property.getDiskUsageBuildInformation(build.getNumber())==null && build.getRootDir().exists()){ - property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); + } + if(action != null) { + //remove old action, now it is added by transition action factory + build.getActions().remove(action); + try { + build.save(); + } catch (IOException ex) { + Logger.getLogger(BuildDiskUsageAction.class.getName()).log(Level.SEVERE, null, ex); } + } + //Transient actions can be created even during deletion of job + if(property.getDiskUsageBuildInformation(build.getNumber()) == null && build.getRootDir().exists()) { + property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); + } } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index e1e4179d..e8811bc7 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -24,77 +24,77 @@ * @author dvrzalik */ @Extension -public class BuildDiskUsageCalculationThread extends DiskUsageCalculation { - +public class BuildDiskUsageCalculationThread extends DiskUsageCalculation { + //last scheduled task; private static DiskUsageCalculation currentTask; - - public BuildDiskUsageCalculationThread(){ - super("Calculation of builds disk usage"); - } - + + public BuildDiskUsageCalculationThread() { + super("Calculation of builds disk usage"); + } + @Override public void execute(TaskListener listener) throws IOException, InterruptedException { - if(!isCancelled() && startExecution()){ - try{ + if(!isCancelled() && startExecution()) { + try { List items = new ArrayList(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); - - for (Object item : items) { - if (item instanceof AbstractProject) { + + for(Object item: items) { + if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - // if (!project.isBuilding()) { - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ - property = new DiskUsageProperty(); - project.addProperty(property); + // if (!project.isBuilding()) { + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + if(property == null) { + property = new DiskUsageProperty(); + project.addProperty(property); + } + ProjectDiskUsage diskUsage = property.getProjectDiskUsage(); + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(true)) { + Map loadedBuilds = project._getRuns().getLoadedBuilds(); + AbstractBuild build = loadedBuilds.get(information.getNumber()); + //do not calculat builds in progress + if(build != null && build.isBuilding()) { + continue; } - ProjectDiskUsage diskUsage = property.getProjectDiskUsage(); - for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(true)){ - Map loadedBuilds = project._getRuns().getLoadedBuilds(); - AbstractBuild build = loadedBuilds.get(information.getNumber()); - //do not calculat builds in progress - if(build!=null && build.isBuilding()){ - continue; - } - try{ - DiskUsageUtil.calculateDiskUsageForBuild(information.getId(), project); - } - catch(Exception e){ - logger.log(Level.WARNING, "Error when recording disk usage for " + project.getName(), e); - } + try { + DiskUsageUtil.calculateDiskUsageForBuild(information.getId(), project); } - // } + catch (Exception e) { + logger.log(Level.WARNING, "Error when recording disk usage for " + project.getName(), e); + } + } + // } } } } catch (Exception ex) { logger.log(Level.WARNING, "Error when recording disk usage for builds", ex); } } - else{ + else { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(plugin.getConfiguration().isCalculationBuildsEnabled()){ + if(plugin.getConfiguration().isCalculationBuildsEnabled()) { logger.log(Level.FINER, "Calculation of builds is already in progress."); } - else{ + else { logger.log(Level.FINER, "Calculation of builds is disabled."); } } } - - public CronTab getCronTab() throws ANTLRException{ + + public CronTab getCronTab() throws ANTLRException { String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); CronTab tab = new CronTab(cron); return tab; - } + } @Override - public AperiodicWork getNewInstance() { - if(currentTask!=null){ + public AperiodicWork getNewInstance() { + if(currentTask != null) { currentTask.cancel(); } - else{ + else { cancel(); } currentTask = new BuildDiskUsageCalculationThread(); @@ -105,13 +105,13 @@ public AperiodicWork getNewInstance() { public DiskUsageCalculation getLastTask() { return currentTask; } - - private boolean startExecution(){ + + private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationBuildsEnabled()) { return false; } return !isExecutingMoreThenOneTimes(); } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsage.java b/src/main/java/hudson/plugins/disk_usage/DiskUsage.java index 33dd95f4..8fc57b1f 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsage.java @@ -11,15 +11,16 @@ */ @Deprecated public class DiskUsage { - - public DiskUsage() {} - - public DiskUsage(Long buildUsage, Long wsUsage){ + + public DiskUsage() { + } + + public DiskUsage(Long buildUsage, Long wsUsage) { this.buildUsage = buildUsage; this.wsUsage = wsUsage; } - + Long buildUsage; Long wsUsage; - + } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java index 7026294d..cebd7f61 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java @@ -19,7 +19,7 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageBuildActionFactory extends TransientActionFactory{ +public class DiskUsageBuildActionFactory extends TransientActionFactory { @Override public Class type() { @@ -28,6 +28,6 @@ public Class type() { @Override public Collection createFor(AbstractBuild t) { - return new ArrayList(Collections.singleton(new BuildDiskUsageAction(t))); + return new ArrayList(Collections.singleton(new BuildDiskUsageAction(t))); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index 8dfbc727..a4b9f78e 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -13,17 +13,17 @@ * * @author Lucie Votypkova */ -public class DiskUsageBuildInformation implements Serializable, Comparable{ - +public class DiskUsageBuildInformation implements Serializable, Comparable { + private static final DateFormat LEGACY_ID_FORMATTER = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); private String id; private long timestamp; private int number; - + private Long size; - - public DiskUsageBuildInformation(String id, long timestamp, int number, Long size){ + + public DiskUsageBuildInformation(String id, long timestamp, int number, Long size) { this.id = id; this.timestamp = timestamp; this.number = number; @@ -31,7 +31,7 @@ public DiskUsageBuildInformation(String id, long timestamp, int number, Long siz } private Object readResolve() { - if (timestamp == 0) { + if(timestamp == 0) { try { timestamp = LEGACY_ID_FORMATTER.parse(id).getTime(); } catch (ParseException x) { @@ -40,47 +40,47 @@ private Object readResolve() { } return this; } - - public String getId(){ + + public String getId() { return id; } public long getTimestamp() { return timestamp; } - - public int getNumber(){ + + public int getNumber() { return number; } - - public Long getSize(){ + + public Long getSize() { if(size == null) { return 0L; } return size; } - + @Override - public boolean equals(Object o){ - if(o instanceof DiskUsageBuildInformation){ + public boolean equals(Object o) { + if(o instanceof DiskUsageBuildInformation) { DiskUsageBuildInformation information = (DiskUsageBuildInformation) o; return information.getId().equals(id); } return false; } - - public int compareTo(Object o){ - if(o instanceof DiskUsageBuildInformation){ + + public int compareTo(Object o) { + if(o instanceof DiskUsageBuildInformation) { return id.compareTo(((DiskUsageBuildInformation) o).getId()); } throw new IllegalArgumentException("Can not compare with different type"); } - - public void setSize(Long size){ + + public void setSize(Long size) { this.size = size; } - - public String toString(){ + + public String toString() { return "Id " + id + " number " + number + " size " + size; } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java index f973aabc..ec70d3eb 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java @@ -12,42 +12,42 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageBuildListener extends RunListener{ - +public class DiskUsageBuildListener extends RunListener { + @Override - public void onCompleted(AbstractBuild build, TaskListener listener){ + public void onCompleted(AbstractBuild build, TaskListener listener) { Long diskUsage = build.getAction(BuildDiskUsageAction.class).getDiskUsage(); - if(build.getProject().getPublishersList().get(DiskUsagePostBuildCalculation.class)==null || diskUsage==0){ - DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); - } - else{ - listener.getLogger().println("Skipping calculation of disk usage, it was already done in post build step."); - } + if(build.getProject().getPublishersList().get(DiskUsagePostBuildCalculation.class) == null || diskUsage == 0) { + DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); + } + else { + listener.getLogger().println("Skipping calculation of disk usage, it was already done in post build step."); } - + } + @Override - public void onDeleted(AbstractBuild build){ + public void onDeleted(AbstractBuild build) { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - if(property==null){ - DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + if(property == null) { + DiskUsageUtil.addProperty(build.getProject()); + property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); - if(information!=null){ + if(information != null) { property.getDiskUsage().removeBuild(information); property.getDiskUsage().save(); } } - + @Override - public void onStarted(AbstractBuild build, TaskListener listener){ + public void onStarted(AbstractBuild build, TaskListener listener) { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - if(property==null){ - DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + if(property == null) { + DiskUsageUtil.addProperty(build.getProject()); + property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); - if(information==null){ + if(information == null) { property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), 0l), build); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 35d83901..677f78a3 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -21,41 +21,41 @@ * * @author lucinka */ -public abstract class DiskUsageCalculation extends AsyncAperiodicWork{ - +public abstract class DiskUsageCalculation extends AsyncAperiodicWork { + private boolean cancelled; - - public DiskUsageCalculation(String name){ - super(name); + + public DiskUsageCalculation(String name) { + super(name); } - + public boolean isExecuting() { - for(Thread t: Thread.getAllStackTraces().keySet()){ + for(Thread t: Thread.getAllStackTraces().keySet()) { if(t.getName().equals(getThreadName())) { return t.isAlive() && !t.isInterrupted(); } } return false; } - + public boolean isExecutingMoreThenOneTimes() { int count = 0; - for(Thread t: Thread.getAllStackTraces().keySet()){ - if(t.getName().equals(getThreadName())){ + for(Thread t: Thread.getAllStackTraces().keySet()) { + if(t.getName().equals(getThreadName())) { if(t.isAlive() && !t.isInterrupted()) { count++; } } } - return count>1; + return count > 1; } - - public String getThreadName(){ - return name +" thread"; + + public String getThreadName() { + return name + " thread"; } - + public abstract DiskUsageCalculation getLastTask(); - + public long scheduledLastInstanceExecutionTime() { try { CronTab tab = null; @@ -63,56 +63,56 @@ public long scheduledLastInstanceExecutionTime() { return 0l; } tab = getLastTask().getCronTab(); - long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); - if(time< new GregorianCalendar().getTimeInMillis()){ - return 0; - } - return time; + long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); + if(time < new GregorianCalendar().getTimeInMillis()) { + return 0; + } + return time; } catch (ANTLRException ex) { Logger.getLogger(DiskUsageCalculation.class.getName()).log(Level.SEVERE, null, ex); return -1; } } - + @Override - public long getInitialDelay(){ + public long getInitialDelay() { return getRecurrencePeriod(); - } - + } + @Override - public boolean cancel(){ - cancelled = true; + public boolean cancel() { + cancelled = true; final ScheduledExecutorService scheduledExecutorService = Timer.get(); - if (scheduledExecutorService instanceof ScheduledThreadPoolExecutor){ + if(scheduledExecutorService instanceof ScheduledThreadPoolExecutor) { ScheduledThreadPoolExecutor ex = (ScheduledThreadPoolExecutor) scheduledExecutorService; ex.purge(); } - return super.cancel(); + return super.cancel(); } - - public boolean isCancelled(){ + + public boolean isCancelled() { return cancelled; } - - public void reschedule(){ - if(getLastTask()==null){ + + public void reschedule() { + if(getLastTask() == null) { cancel(); } - else{ - getLastTask().cancel(); + else { + getLastTask().cancel(); } Timer.get().schedule(getNewInstance(), getRecurrencePeriod(), TimeUnit.MILLISECONDS); - + try { Thread.sleep(60000); } catch (InterruptedException ex) { Logger.getLogger(DiskUsageCalculation.class.getName()).log(Level.SEVERE, null, ex); } } - + public abstract CronTab getCronTab() throws ANTLRException; - + @Override public long getRecurrencePeriod() { try { @@ -123,12 +123,12 @@ public long getRecurrencePeriod() { if(nextExecution.getTimeInMillis() - now.getTimeInMillis() <= 60000) { period = period + 60000l; //add one minute to not shedule it during one minute one than once } - return period; + return period; } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); //it should not happen - return 1000*60*6; + return 1000 * 60 * 6; } } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java index dd8af15b..2d1db419 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageGraph.java @@ -27,74 +27,74 @@ * * @author jbrazdil */ -public class DiskUsageGraph extends Graph{ - CategoryDataset dataset; - CategoryDataset workspaceDataset; - String unit; - String workspaceUnit; +public class DiskUsageGraph extends Graph { + CategoryDataset dataset; + CategoryDataset workspaceDataset; + String unit; + String workspaceUnit; - public DiskUsageGraph(CategoryDataset dataset, String unit, CategoryDataset workspaceDataset, String workspaceUnit){ - super(-1, 350, 150); - this.workspaceDataset = workspaceDataset; - this.dataset = dataset; - this.unit = unit; - this.workspaceUnit = workspaceUnit; - } + public DiskUsageGraph(CategoryDataset dataset, String unit, CategoryDataset workspaceDataset, String workspaceUnit) { + super(-1, 350, 150); + this.workspaceDataset = workspaceDataset; + this.dataset = dataset; + this.unit = unit; + this.workspaceUnit = workspaceUnit; + } - @Override - protected JFreeChart createGraph() { - final JFreeChart chart = ChartFactory.createAreaChart( - null, // chart title - null, // unused - Messages.DiskUsage_Graph_JobDiskUsageAxis() + " [" + unit + "]", // range axis label - dataset, // data - PlotOrientation.VERTICAL, // orientation - true, // include legend - true, // tooltips - false // urls - ); + @Override + protected JFreeChart createGraph() { + final JFreeChart chart = ChartFactory.createAreaChart( + null, // chart title + null, // unused + Messages.DiskUsage_Graph_JobDiskUsageAxis() + " [" + unit + "]", // range axis label + dataset, // data + PlotOrientation.VERTICAL, // orientation + true, // include legend + true, // tooltips + false // urls + ); - final LegendTitle legend = chart.getLegend(); - legend.setPosition(RectangleEdge.BOTTOM); + final LegendTitle legend = chart.getLegend(); + legend.setPosition(RectangleEdge.BOTTOM); - chart.setBackgroundPaint(Color.white); - CategoryPlot plot = (CategoryPlot) chart.getPlot(); + chart.setBackgroundPaint(Color.white); + CategoryPlot plot = (CategoryPlot) chart.getPlot(); - plot.setBackgroundPaint(Color.WHITE); - plot.setOutlinePaint(null); - plot.setRangeGridlinesVisible(true); - plot.setRangeGridlinePaint(Color.black); - CategoryAxis domainAxis = new ShiftedCategoryAxis(null); - plot.setDomainAxis(domainAxis); - domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); - domainAxis.setLowerMargin(0.0); - domainAxis.setUpperMargin(0.0); - // voodoo for better spacing between labels with many columns - domainAxis.setCategoryMargin(-((double) dataset.getColumnCount() / 10.0)); - plot.setDataset(1, workspaceDataset); - LineAndShapeRenderer renderer = new LineAndShapeRenderer(); - renderer.setBaseShapesVisible(false); - renderer.setSeriesStroke(0, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL)); - renderer.setSeriesStroke(1, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL)); - plot.setRenderer(1, renderer); - ValueAxis rangeAxis = new NumberAxis(Messages.DiskUsage_Graph_WorkspaceDiskUsageAxis() + " [" + workspaceUnit + "]"); - plot.setRangeAxis(1, rangeAxis); - plot.mapDatasetToRangeAxis(1, 1); - setColorForArea(plot.getRenderer(), dataset.getRowCount() > 2); - plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); - renderer.setSeriesPaint(1, new Color(255, 204, 0)); - return chart; - } + plot.setBackgroundPaint(Color.WHITE); + plot.setOutlinePaint(null); + plot.setRangeGridlinesVisible(true); + plot.setRangeGridlinePaint(Color.black); + CategoryAxis domainAxis = new ShiftedCategoryAxis(null); + plot.setDomainAxis(domainAxis); + domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); + domainAxis.setLowerMargin(0.0); + domainAxis.setUpperMargin(0.0); + // voodoo for better spacing between labels with many columns + domainAxis.setCategoryMargin(-((double) dataset.getColumnCount() / 10.0)); + plot.setDataset(1, workspaceDataset); + LineAndShapeRenderer renderer = new LineAndShapeRenderer(); + renderer.setBaseShapesVisible(false); + renderer.setSeriesStroke(0, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL)); + renderer.setSeriesStroke(1, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL)); + plot.setRenderer(1, renderer); + ValueAxis rangeAxis = new NumberAxis(Messages.DiskUsage_Graph_WorkspaceDiskUsageAxis() + " [" + workspaceUnit + "]"); + plot.setRangeAxis(1, rangeAxis); + plot.mapDatasetToRangeAxis(1, 1); + setColorForArea(plot.getRenderer(), dataset.getRowCount() > 2); + plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); + renderer.setSeriesPaint(1, new Color(255, 204, 0)); + return chart; + } - public void setColorForArea(CategoryItemRenderer renderer, boolean global){ - if(global){ - renderer.setSeriesPaint(0, Color.LIGHT_GRAY); - renderer.setSeriesPaint(1, new Color(60, 179, 113)); - renderer.setSeriesPaint(2, new Color(106, 90, 205)); - } - else{ - renderer.setSeriesPaint(0, new Color(60, 179, 113)); - renderer.setSeriesPaint(1, new Color(106, 90, 205)); - } - } + public void setColorForArea(CategoryItemRenderer renderer, boolean global) { + if(global) { + renderer.setSeriesPaint(0, Color.LIGHT_GRAY); + renderer.setSeriesPaint(1, new Color(60, 179, 113)); + renderer.setSeriesPaint(2, new Color(106, 90, 205)); + } + else { + renderer.setSeriesPaint(0, new Color(60, 179, 113)); + renderer.setSeriesPaint(1, new Color(106, 90, 205)); + } + } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java index 1f00864c..2784187f 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java @@ -16,36 +16,36 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageItemListener extends ItemListener{ - +public class DiskUsageItemListener extends ItemListener { + @Override public void onDeleted(Item item) { if(item instanceof AbstractProject) { DiskUsageProjectActionFactory.DESCRIPTOR.onDeleteJob((AbstractProject) item); - } + } } - + @Override - public void onRenamed(Item item, String oldName, String newName) { + public void onRenamed(Item item, String oldName, String newName) { if(item instanceof AbstractProject) { DiskUsageProjectActionFactory.DESCRIPTOR.onRenameJob(oldName, newName); } - } - + } + @Override - public void onCreated(Item item){ + public void onCreated(Item item) { DiskUsageUtil.addProperty(item); - } - + } + @Override - public void onCopied(Item src, Item item){ + public void onCopied(Item src, Item item) { DiskUsageUtil.addProperty(item); } - + @Override - public void onLoaded(){ - for(Item item : Jenkins.getInstance().getItems()){ + public void onLoaded() { + for(Item item: Jenkins.getInstance().getItems()) { DiskUsageUtil.addProperty(item); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 0ca7a15f..24f5f870 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -18,29 +18,30 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageManagement extends ManagementLink implements RootAction{ - - public final String[] COLUMNS = new String[]{"Project name", "Builds", "Workspace", "JobDirectory (without builds)"}; - - public String getIconFileName() { - return "/plugin/disk-usage/icons/diskusage48.png"; - } - - public String getDisplayName() { - return Messages.DisplayName(); - } - - public String getUrlName() { - return "disk-usage"; - } - - @Override public String getDescription() { - return Messages.Description(); - } - - public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException{ - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - res.sendRedirect(Jenkins.getInstance().getRootUrlFromRequest() + "plugin/disk-usage"); - } - +public class DiskUsageManagement extends ManagementLink implements RootAction { + + public final String[] COLUMNS = new String[]{"Project name", "Builds", "Workspace", "JobDirectory (without builds)"}; + + public String getIconFileName() { + return "/plugin/disk-usage/icons/diskusage48.png"; + } + + public String getDisplayName() { + return Messages.DisplayName(); + } + + public String getUrlName() { + return "disk-usage"; + } + + @Override + public String getDescription() { + return Messages.Description(); + } + + public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { + DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + res.sendRedirect(Jenkins.getInstance().getRootUrlFromRequest() + "plugin/disk-usage"); + } + } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 565b5ac8..8df71590 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -18,90 +18,90 @@ @Extension public class DiskUsageOvearallGraphGenerator extends PeriodicWork { - @Override - public long getRecurrencePeriod() { - return PeriodicWork.DAY; - } - - @Override - protected void doRun() throws Exception { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - plugin.refreshGlobalInformation(); - File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); - Long freeJobsDirSpace = jobsDir.getTotalSpace(); - - DiskUsageProjectActionFactory.DESCRIPTOR.addHistory(new DiskUsageOvearallGraphGenerator.DiskUsageRecord(plugin.getCashedGlobalBuildsDiskUsage(), plugin.getGlobalSlaveDiskUsageWorkspace(), plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), freeJobsDirSpace, plugin.getCashedNonSlaveDiskUsageWorkspace())); - DiskUsageProjectActionFactory.DESCRIPTOR.save(); - } - - public static class DiskUsageRecord extends DiskUsage{ - private static SimpleDateFormat sdf = new SimpleDateFormat("d/M"); - Date date; - private Long jobsWithoutBuildsUsage = 0l; - private Long allSpace = 0l; - private Long diskUsageNonSlaveWorkspaces = 0l; - - - public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces){ - super(diskUsageBuilds, diskUsageWorkspaces); - this.jobsWithoutBuildsUsage = diskUsageJobsWithoutBuilds; - this.allSpace = allSpace; - this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; - date = new Date(){ - private static final long serialVersionUID = 1L; - @Override - public String toString(){ - return sdf.format(this); - } - }; - } - - public Long getNonSlaveWorkspacesUsage(){ - if(diskUsageNonSlaveWorkspaces == null) { - return 0l; - } - return diskUsageNonSlaveWorkspaces; - } - - public Long getSlaveWorkspacesUsage(){ - if(diskUsageNonSlaveWorkspaces == null) { - return getWorkspacesDiskUsage(); - } - return getWorkspacesDiskUsage() - diskUsageNonSlaveWorkspaces; - } - - public Long getBuildsDiskUsage(){ - if(buildUsage == null) { - return 0l; - } - return buildUsage; - } - - public Long getJobsDiskUsage(){ - if(jobsWithoutBuildsUsage == null) { - return getBuildsDiskUsage(); - } - return jobsWithoutBuildsUsage + getBuildsDiskUsage(); - } - - public Long getAllSpace(){ - if(allSpace == null) { - return 0l; - } - return allSpace; - } - - public Long getWorkspacesDiskUsage(){ - if(wsUsage == null) { - return 0l; - } - return wsUsage; + @Override + public long getRecurrencePeriod() { + return PeriodicWork.DAY; + } + + @Override + protected void doRun() throws Exception { + DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + plugin.refreshGlobalInformation(); + File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); + Long freeJobsDirSpace = jobsDir.getTotalSpace(); + + DiskUsageProjectActionFactory.DESCRIPTOR.addHistory(new DiskUsageOvearallGraphGenerator.DiskUsageRecord(plugin.getCashedGlobalBuildsDiskUsage(), plugin.getGlobalSlaveDiskUsageWorkspace(), plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), freeJobsDirSpace, plugin.getCashedNonSlaveDiskUsageWorkspace())); + DiskUsageProjectActionFactory.DESCRIPTOR.save(); + } + + public static class DiskUsageRecord extends DiskUsage { + private static SimpleDateFormat sdf = new SimpleDateFormat("d/M"); + Date date; + private Long jobsWithoutBuildsUsage = 0l; + private Long allSpace = 0l; + private Long diskUsageNonSlaveWorkspaces = 0l; + + + public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { + super(diskUsageBuilds, diskUsageWorkspaces); + this.jobsWithoutBuildsUsage = diskUsageJobsWithoutBuilds; + this.allSpace = allSpace; + this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; + date = new Date(){ + private static final long serialVersionUID = 1L; + @Override + public String toString() { + return sdf.format(this); } + }; + } + + public Long getNonSlaveWorkspacesUsage() { + if(diskUsageNonSlaveWorkspaces == null) { + return 0l; + } + return diskUsageNonSlaveWorkspaces; + } + + public Long getSlaveWorkspacesUsage() { + if(diskUsageNonSlaveWorkspaces == null) { + return getWorkspacesDiskUsage(); + } + return getWorkspacesDiskUsage() - diskUsageNonSlaveWorkspaces; + } + + public Long getBuildsDiskUsage() { + if(buildUsage == null) { + return 0l; + } + return buildUsage; + } + + public Long getJobsDiskUsage() { + if(jobsWithoutBuildsUsage == null) { + return getBuildsDiskUsage(); + } + return jobsWithoutBuildsUsage + getBuildsDiskUsage(); + } + + public Long getAllSpace() { + if(allSpace == null) { + return 0l; + } + return allSpace; + } + + public Long getWorkspacesDiskUsage() { + if(wsUsage == null) { + return 0l; + } + return wsUsage; + } + + Date getDate() { + return date; + } + } - Date getDate(){ - return date; - } - } - } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index f37a6c0e..277b4d43 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -28,24 +28,24 @@ */ @Extension public class DiskUsagePlugin extends Plugin { - + private Long diskUsageBuilds = 0l; private Long diskUsageJobsWithoutBuilds = 0l; private Long diskUsageWorkspaces = 0l; private Long diskUsageLockedBuilds = 0l; private Long diskUsageNonSlaveWorkspaces = 0l; - - public DiskUsagePlugin(){ + + public DiskUsagePlugin() { } - - public void refreshGlobalInformation() throws IOException{ + + public void refreshGlobalInformation() throws IOException { diskUsageBuilds = 0l; diskUsageWorkspaces = 0l; diskUsageJobsWithoutBuilds = 0l; diskUsageLockedBuilds = 0l; diskUsageNonSlaveWorkspaces = 0l; - for(Item item: Jenkins.getInstance().getItems()){ - if(item instanceof AbstractProject){ + for(Item item: Jenkins.getInstance().getItems()) { + if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; ProjectDiskUsageAction action = (ProjectDiskUsageAction) project.getAction(ProjectDiskUsageAction.class); diskUsageBuilds += action.getBuildsDiskUsage().get("all"); @@ -56,78 +56,78 @@ public void refreshGlobalInformation() throws IOException{ } } } - - public Long getCashedGlobalBuildsDiskUsage(){ + + public Long getCashedGlobalBuildsDiskUsage() { return diskUsageBuilds; } - - public Long getCashedGlobalJobsDiskUsage(){ + + public Long getCashedGlobalJobsDiskUsage() { return diskUsageBuilds + diskUsageJobsWithoutBuilds; } - - public Long getCashedGlobalJobsWithoutBuildsDiskUsage(){ + + public Long getCashedGlobalJobsWithoutBuildsDiskUsage() { return diskUsageJobsWithoutBuilds; } - - public Long getCashedGlobalLockedBuildsDiskUsage(){ - return diskUsageLockedBuilds; + + public Long getCashedGlobalLockedBuildsDiskUsage() { + return diskUsageLockedBuilds; } - - public Long getCashedGlobalWorkspacesDiskUsage(){ + + public Long getCashedGlobalWorkspacesDiskUsage() { return diskUsageWorkspaces; } - - public Long getCashedNonSlaveDiskUsageWorkspace(){ + + public Long getCashedNonSlaveDiskUsageWorkspace() { return diskUsageNonSlaveWorkspaces; } - - public Long getCashedSlaveDiskUsageWorkspace(){ + + public Long getCashedSlaveDiskUsageWorkspace() { return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; } - - public Long getGlobalBuildsDiskUsage() throws IOException{ + + public Long getGlobalBuildsDiskUsage() throws IOException { refreshGlobalInformation(); return diskUsageBuilds; } - - public Long getGlobalJobsDiskUsage() throws IOException{ + + public Long getGlobalJobsDiskUsage() throws IOException { refreshGlobalInformation(); return diskUsageBuilds + diskUsageJobsWithoutBuilds; } - - public Long getGlobalJobsWithoutBuildsDiskUsage() throws IOException{ + + public Long getGlobalJobsWithoutBuildsDiskUsage() throws IOException { refreshGlobalInformation(); return diskUsageJobsWithoutBuilds; } - - public Long getGlobalWorkspacesDiskUsage() throws IOException{ + + public Long getGlobalWorkspacesDiskUsage() throws IOException { refreshGlobalInformation(); return diskUsageWorkspaces; } - - - public Long getGlobalNonSlaveDiskUsageWorkspace() throws IOException{ + + + public Long getGlobalNonSlaveDiskUsageWorkspace() throws IOException { refreshGlobalInformation(); return diskUsageNonSlaveWorkspaces; } - - public Long getGlobalSlaveDiskUsageWorkspace() throws IOException{ + + public Long getGlobalSlaveDiskUsageWorkspace() throws IOException { refreshGlobalInformation(); return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; } - - public BuildDiskUsageCalculationThread getBuildsDiskUsageThread(){ + + public BuildDiskUsageCalculationThread getBuildsDiskUsageThread() { return AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); } - - public JobWithoutBuildsDiskUsageCalculation getJobsDiskUsageThread(){ + + public JobWithoutBuildsDiskUsageCalculation getJobsDiskUsageThread() { return AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); } - - public WorkspaceDiskUsageCalculationThread getWorkspaceDiskUsageThread(){ - return AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); + + public WorkspaceDiskUsageCalculationThread getWorkspaceDiskUsageThread() { + return AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); } - + /** * @return DiskUsage for given project (shortcut for the view). Never null. */ @@ -135,11 +135,11 @@ public ProjectDiskUsageAction getDiskUsage(Job project) { ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); return action; } - - public String getDiskUsageInString(Long size){ + + public String getDiskUsageInString(Long size) { return DiskUsageUtil.getSizeString(size); } - + /** * @return Project list sorted by occupied disk space */ @@ -148,7 +148,7 @@ public List getProjectList() throws IOException { Comparator comparator = new Comparator() { public int compare(AbstractProject o1, AbstractProject o2) { - + ProjectDiskUsageAction dua1 = getDiskUsage(o1); ProjectDiskUsageAction dua2 = getDiskUsage(o2); long result = dua2.getJobRootDirDiskUsage() + dua2.getAllDiskUsageWorkspace() - dua1.getJobRootDirDiskUsage() - dua1.getAllDiskUsageWorkspace(); @@ -168,37 +168,37 @@ public int compare(AbstractProject o1, AbstractProject o2) { return projectList; } - - public void doFilter(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException{ + + public void doFilter(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { Date older = DiskUsageUtil.getDate(req.getParameter("older"), req.getParameter("olderUnit")); Date younger = DiskUsageUtil.getDate(req.getParameter("younger"), req.getParameter("youngerUnit")); req.setAttribute("filter", "filter"); req.setAttribute("older", older); req.setAttribute("younger", younger); - - req.getView(this, "index.jelly").forward(req, rsp); + + req.getView(this, "index.jelly").forward(req, rsp); } - - public DiskUsageProjectActionFactory.DescriptorImpl getConfiguration(){ + + public DiskUsageProjectActionFactory.DescriptorImpl getConfiguration() { return DiskUsageProjectActionFactory.DESCRIPTOR; } - - public Graph getOverallGraph(){ + + public Graph getOverallGraph() { File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); long maxValue = getCashedGlobalJobsDiskUsage(); - if(getConfiguration().getShowFreeSpaceForJobDirectory()){ + if(getConfiguration().getShowFreeSpaceForJobDirectory()) { maxValue = jobsDir.getTotalSpace(); } long maxValueWorkspace = Math.max(diskUsageNonSlaveWorkspaces, getCashedSlaveDiskUsageWorkspace()); List record = DiskUsageProjectActionFactory.DESCRIPTOR.getHistory(); //First iteration just to get scale of the y-axis - for (DiskUsageOvearallGraphGenerator.DiskUsageRecord usage : record){ - if(getConfiguration().getShowFreeSpaceForJobDirectory()){ + for(DiskUsageOvearallGraphGenerator.DiskUsageRecord usage: record) { + if(getConfiguration().getShowFreeSpaceForJobDirectory()) { maxValue = Math.max(maxValue, usage.getAllSpace()); } maxValue = Math.max(maxValue, usage.getJobsDiskUsage()); maxValueWorkspace = Math.max(maxValueWorkspace, usage.getSlaveWorkspacesUsage()); - maxValueWorkspace = Math.max(maxValueWorkspace, usage.getNonSlaveWorkspacesUsage()); + maxValueWorkspace = Math.max(maxValueWorkspace, usage.getNonSlaveWorkspacesUsage()); } int floor = (int) DiskUsageUtil.getScale(maxValue); int floorWorkspace = (int) DiskUsageUtil.getScale(maxValueWorkspace); @@ -208,28 +208,28 @@ public Graph getOverallGraph(){ double baseWorkspace = Math.pow(1024, floorWorkspace); DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset datasetW = new DefaultCategoryDataset(); - for (DiskUsageOvearallGraphGenerator.DiskUsageRecord usage : record) { + for(DiskUsageOvearallGraphGenerator.DiskUsageRecord usage: record) { Date label = usage.getDate(); - if(getConfiguration().getShowFreeSpaceForJobDirectory()){ + if(getConfiguration().getShowFreeSpaceForJobDirectory()) { dataset.addValue(((Long) usage.getAllSpace()) / base, "space for jobs directory", label); } dataset.addValue(((Long) usage.getJobsDiskUsage()) / base, "all jobs", label); dataset.addValue(((Long) usage.getBuildsDiskUsage()) / base, "all builds", label); - datasetW.addValue(((Long) usage.getSlaveWorkspacesUsage()) / baseWorkspace, "slave workspaces", label); - datasetW.addValue(((Long) usage.getNonSlaveWorkspacesUsage()) / baseWorkspace, "non slave workspaces", label); + datasetW.addValue(((Long) usage.getSlaveWorkspacesUsage()) / baseWorkspace, "slave workspaces", label); + datasetW.addValue(((Long) usage.getNonSlaveWorkspacesUsage()) / baseWorkspace, "non slave workspaces", label); } - + //add current state - if(getConfiguration().getShowFreeSpaceForJobDirectory()){ - dataset.addValue(((Long) jobsDir.getTotalSpace()) / base, "space for jobs directory", "current"); + if(getConfiguration().getShowFreeSpaceForJobDirectory()) { + dataset.addValue(((Long) jobsDir.getTotalSpace()) / base, "space for jobs directory", "current"); } dataset.addValue(((Long) getCashedGlobalJobsDiskUsage()) / base, "all jobs", "current"); dataset.addValue(((Long) getCashedGlobalBuildsDiskUsage()) / base, "all builds", "current"); datasetW.addValue(((Long) getCashedSlaveDiskUsageWorkspace()) / baseWorkspace, "slave workspaces", "current"); datasetW.addValue(((Long) getCashedNonSlaveDiskUsageWorkspace()) / baseWorkspace, "non slave workspaces", "current"); return new DiskUsageGraph(dataset, unit, datasetW, unitWorkspace); - } - + } + public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationBuildsEnabled() && !getBuildsDiskUsageThread().isExecuting()) { @@ -237,7 +237,7 @@ public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) thro } res.forwardToPreviousPage(req); } - + public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationJobsEnabled() && !getJobsDiskUsageThread().isExecuting()) { @@ -245,7 +245,7 @@ public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throw } res.forwardToPreviousPage(req); } - + public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationWorkspaceEnabled() && !getWorkspaceDiskUsageThread().isExecuting()) { @@ -253,34 +253,34 @@ public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) } res.forwardToPreviousPage(req); } - - - public String getCountIntervalForBuilds(){ + + + public String getCountIntervalForBuilds() { long nextExecution = getBuildsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution <= 0) { //not scheduled nextExecution = getBuildsDiskUsageThread().getRecurrencePeriod(); - } + } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } - - public String getCountIntervalForJobs(){ + + public String getCountIntervalForJobs() { long nextExecution = getJobsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution <= 0) { //not scheduled nextExecution = getJobsDiskUsageThread().getRecurrencePeriod(); } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } - - public String getCountIntervalForWorkspaces(){ + + public String getCountIntervalForWorkspaces() { long nextExecution = getWorkspaceDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution <= 0) { //not scheduled nextExecution = getWorkspaceDiskUsageThread().getRecurrencePeriod(); } return DiskUsageUtil.formatTimeInMilisec(nextExecution); } - - public boolean hasAdministrativePermission(){ + + public boolean hasAdministrativePermission() { return Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER); } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 8d3c6ac7..0ab5a7b7 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -40,362 +40,362 @@ public DescriptorImpl() { load(); } - private String countIntervalBuilds = "0 */6 * * *"; - + private String countIntervalBuilds = "0 */6 * * *"; + private boolean calculationBuilds = true; - + private String countIntervalJobs = "0 */6 * * *"; - + private boolean calculationJobs = true; - - private String countIntervalWorkspace ="0 */6 * * *"; - + + private String countIntervalWorkspace = "0 */6 * * *"; + private boolean calculationWorkspace = true; - + private boolean checkWorkspaceOnSlave = false; - + private String email; - + private String jobSize; - + private String buildSize; - + private String allJobsSize; - - private String jobWorkspaceExceedSize; - + + private String jobWorkspaceExceedSize; + private boolean showFreeSpaceForJobDirectory = true; - + private List excludedJobs = new ArrayList(); - + private Long diskUsageBuilds = 0l; private Long diskUsageJobsWithoutBuilds = 0l; private Long diskUsageWorkspaces = 0l; private Long diskUsageLockedBuilds = 0l; - + private boolean showGraph = true; private int historyLength = 183; List history = new LinkedList(){ - private static final long serialVersionUID = 1L; - - @Override - public boolean add(DiskUsageOvearallGraphGenerator.DiskUsageRecord e) { - boolean ret = super.add(e); - if(ret && this.size() > historyLength){ - this.removeRange(0, this.size() - historyLength); - } - return ret; - } - }; + private static final long serialVersionUID = 1L; + + @Override + public boolean add(DiskUsageOvearallGraphGenerator.DiskUsageRecord e) { + boolean ret = super.add(e); + if(ret && this.size() > historyLength) { + this.removeRange(0, this.size() - historyLength); + } + return ret; + } + }; // Timeout for a single Project's workspace analyze (in mn) private int timeoutWorkspace = 5; - - public Long getCashedGlobalBuildsDiskUsage(){ - return diskUsageBuilds; - } - - public Long getCashedGlobalJobsDiskUsage(){ - return diskUsageBuilds + diskUsageJobsWithoutBuilds; - } - - public Long getCashedGlobalJobsWithoutBuildsDiskUsage(){ - return diskUsageJobsWithoutBuilds; - } - - public Long getCashedGlobalLockedBuildsDiskUsage(){ - return diskUsageLockedBuilds; - } - - public Long getCashedGlobalWorkspacesDiskUsage(){ - return diskUsageWorkspaces; - } - - public Long getJobWorkspaceExceedSize(){ - return DiskUsageUtil.getSizeInBytes(jobWorkspaceExceedSize); - } - - public String getJobWorkspaceExceedSizeInString(){ - return jobWorkspaceExceedSize; - } - - public boolean isShowGraph() { - return showGraph; - } - public void setShowGraph(Boolean showGraph) { - this.showGraph = showGraph; - } + public Long getCashedGlobalBuildsDiskUsage() { + return diskUsageBuilds; + } - public int getHistoryLength() { - return historyLength; - } + public Long getCashedGlobalJobsDiskUsage() { + return diskUsageBuilds + diskUsageJobsWithoutBuilds; + } - public void setHistoryLength(Integer historyLength) { - this.historyLength = historyLength; - } + public Long getCashedGlobalJobsWithoutBuildsDiskUsage() { + return diskUsageJobsWithoutBuilds; + } - public List getHistory(){ - return history; - } + public Long getCashedGlobalLockedBuildsDiskUsage() { + return diskUsageLockedBuilds; + } - public String getCountIntervalForBuilds(){ - return countIntervalBuilds; - } - - public String getCountIntervalForJobs(){ - return countIntervalJobs; - } - - public String getCountIntervalForWorkspaces(){ - return countIntervalWorkspace; - } - - public boolean getCheckWorkspaceOnSlave(){ - return checkWorkspaceOnSlave; - } - - public void setCheckWorkspaceOnSlave(boolean check){ - checkWorkspaceOnSlave = check; - } - - public void setExcludedJobs(List excludedJobs){ - this.excludedJobs = excludedJobs; - } - - public boolean isCalculationWorkspaceEnabled(){ - return calculationWorkspace; - } - - public boolean isCalculationBuildsEnabled(){ - return calculationBuilds; - } - - public boolean isCalculationJobsEnabled(){ - return calculationJobs; - } - - public boolean warnAboutJobWorkspaceExceedSize(){ - return jobWorkspaceExceedSize!=null; - } - - public boolean warnAboutAllJobsExceetedSize(){ - return allJobsSize!=null; - } - - public boolean warnAboutBuildExceetedSize(){ - return buildSize!=null; - } - - public boolean warnAboutJobExceetedSize(){ - return jobSize!=null; - } + public Long getCashedGlobalWorkspacesDiskUsage() { + return diskUsageWorkspaces; + } - public String getEmailAddress(){ - return email; - } - - public boolean warningAboutExceededSize(){ - return email!=null; - } - - public Long getAllJobsExceedSize(){ - return DiskUsageUtil.getSizeInBytes(allJobsSize); - } - - public Long getBuildExceedSize(){ - return DiskUsageUtil.getSizeInBytes(buildSize); - } - - public Long getJobExceedSize(){ - return DiskUsageUtil.getSizeInBytes(jobSize); - } - - public String getAllJobsExceedSizeInString(){ - return allJobsSize; - } - - public String getBuildExceedSizeInString(){ - return buildSize; - } - - public String getJobExceedSizeInString(){ - return jobSize; - } + public Long getJobWorkspaceExceedSize() { + return DiskUsageUtil.getSizeInBytes(jobWorkspaceExceedSize); + } - public boolean addHistory(DiskUsageOvearallGraphGenerator.DiskUsageRecord e) { - boolean ok = history.add(e); - save(); - return ok; - } - - public void enableBuildsDiskUsageCalculation(){ - calculationBuilds=true; - } - - public void disableBuildsDiskUsageCalculation(){ - calculationBuilds=false; - } - - public void enableJobsDiskUsageCalculation(){ - calculationJobs=true; - } - - public void disableJobsDiskUsageCalculation(){ - calculationJobs=false; - } - - public void enableWorkspacesDiskUsageCalculation(){ - calculationWorkspace=true; - } - - public void disableWorkspacesDiskUsageCalculation(){ - calculationWorkspace=false; - } - - public String getUnit(String unit){ - if(unit == null) { - return null; + public String getJobWorkspaceExceedSizeInString() { + return jobWorkspaceExceedSize; } - return unit.split(" ")[1]; - } - - public String getValue(String size){ - if(size == null) { - return null; + + public boolean isShowGraph() { + return showGraph; } - return size.split(" ")[0]; - } + public void setShowGraph(Boolean showGraph) { + this.showGraph = showGraph; + } - @Override - public String getDisplayName() { - return Messages.DisplayName(); - } + public int getHistoryLength() { + return historyLength; + } + public void setHistoryLength(Integer historyLength) { + this.historyLength = historyLength; + } - @Override - public DiskUsageProjectActionFactory newInstance(StaplerRequest req, JSONObject formData) { - return new DiskUsageProjectActionFactory(); - } + public List getHistory() { + return history; + } + public String getCountIntervalForBuilds() { + return countIntervalBuilds; + } - @Override - public boolean configure(StaplerRequest req, JSONObject formData) { - Jenkins.getInstance().checkPermission(Permission.CONFIGURE); - JSONObject form; - try { - form = req.getSubmittedForm(); - } catch (ServletException ex) { - Logger.getLogger(DiskUsageProjectActionFactory.class.getName()).log(Level.SEVERE, null, ex); - return false; - } - //workspaceTimeOut = form.getInt("countInterval"); - checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnSlave"); - configureBuildsCalculation(form); - configureJobsCalculation(form); - configureWorkspacesCalculation(form); - String excluded = form.getString("excludedJobs"); - excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); - if(form.containsKey("warnings")){ - JSONObject warnings = form.getJSONObject("warnings"); - email = warnings.getString("email"); - if(email!=null){ - allJobsSize = warnings.containsKey("jobsWarning")? (warnings.getJSONObject("jobsWarning").getInt("allJobsSize") + " " + warnings.getJSONObject("jobsWarning").getString("JobsSizeUnit")) : null; - buildSize = warnings.containsKey("buildWarning")? (warnings.getJSONObject("buildWarning").getInt("buildSize") + " " + warnings.getJSONObject("buildWarning").getString("buildSizeUnit")) : null; - jobSize = warnings.containsKey("jobWarning")? (warnings.getJSONObject("jobWarning").getInt("jobSize") + " " + warnings.getJSONObject("jobWarning").getString("jobSizeUnit")) : null; - jobWorkspaceExceedSize = warnings.containsKey("workspaceWarning")? (warnings.getJSONObject("workspaceWarning").getInt("jobWorkspaceExceedSize") + " " + warnings.getJSONObject("workspaceWarning").getString("jobWorkspaceExceedSizeUnit")) : null; + public String getCountIntervalForJobs() { + return countIntervalJobs; + } + + public String getCountIntervalForWorkspaces() { + return countIntervalWorkspace; + } + + public boolean getCheckWorkspaceOnSlave() { + return checkWorkspaceOnSlave; + } + + public void setCheckWorkspaceOnSlave(boolean check) { + checkWorkspaceOnSlave = check; + } + + public void setExcludedJobs(List excludedJobs) { + this.excludedJobs = excludedJobs; + } + + public boolean isCalculationWorkspaceEnabled() { + return calculationWorkspace; + } + + public boolean isCalculationBuildsEnabled() { + return calculationBuilds; + } + + public boolean isCalculationJobsEnabled() { + return calculationJobs; + } + + public boolean warnAboutJobWorkspaceExceedSize() { + return jobWorkspaceExceedSize != null; + } + + public boolean warnAboutAllJobsExceetedSize() { + return allJobsSize != null; + } + + public boolean warnAboutBuildExceetedSize() { + return buildSize != null; + } + + public boolean warnAboutJobExceetedSize() { + return jobSize != null; + } + + public String getEmailAddress() { + return email; + } + + public boolean warningAboutExceededSize() { + return email != null; + } + + public Long getAllJobsExceedSize() { + return DiskUsageUtil.getSizeInBytes(allJobsSize); + } + + public Long getBuildExceedSize() { + return DiskUsageUtil.getSizeInBytes(buildSize); + } + + public Long getJobExceedSize() { + return DiskUsageUtil.getSizeInBytes(jobSize); + } + + public String getAllJobsExceedSizeInString() { + return allJobsSize; + } + + public String getBuildExceedSizeInString() { + return buildSize; + } + + public String getJobExceedSizeInString() { + return jobSize; + } + + public boolean addHistory(DiskUsageOvearallGraphGenerator.DiskUsageRecord e) { + boolean ok = history.add(e); + save(); + return ok; + } + + public void enableBuildsDiskUsageCalculation() { + calculationBuilds = true; + } + + public void disableBuildsDiskUsageCalculation() { + calculationBuilds = false; + } + + public void enableJobsDiskUsageCalculation() { + calculationJobs = true; + } + + public void disableJobsDiskUsageCalculation() { + calculationJobs = false; + } + + public void enableWorkspacesDiskUsageCalculation() { + calculationWorkspace = true; + } + + public void disableWorkspacesDiskUsageCalculation() { + calculationWorkspace = false; + } + + public String getUnit(String unit) { + if(unit == null) { + return null; } + return unit.split(" ")[1]; } - showGraph = form.getBoolean("showGraph"); - String histlen = req.getParameter("historyLength"); - if(histlen != null && !histlen.isEmpty()){ - historyLength = Integer.parseInt(histlen); - } - timeoutWorkspace = form.getInt("timeoutWorkspace"); - showFreeSpaceForJobDirectory = form.getBoolean("showFreeSpaceForJobDirectory"); - save(); - return true; - } - - public void onRenameJob(String oldName, String newName){ - if(excludedJobs.contains(oldName)){ - excludedJobs.remove(oldName); - excludedJobs.add(newName); - } - } - - public void onDeleteJob(AbstractProject project){ - String name = project.getName(); - if(excludedJobs.contains(name)){ - excludedJobs.remove(name); - } - } - - public boolean isExcluded(AbstractProject project){ - return excludedJobs.contains(project.getName()); - } - - public String getExcludedJobsInString(){ - StringBuilder builder = new StringBuilder(); - boolean first = true; - for(String name: excludedJobs){ - if(first){ - first= false; + + public String getValue(String size) { + if(size == null) { + return null; + } + return size.split(" ")[0]; + } + + + @Override + public String getDisplayName() { + return Messages.DisplayName(); + } + + + @Override + public DiskUsageProjectActionFactory newInstance(StaplerRequest req, JSONObject formData) { + return new DiskUsageProjectActionFactory(); + } + + + @Override + public boolean configure(StaplerRequest req, JSONObject formData) { + Jenkins.getInstance().checkPermission(Permission.CONFIGURE); + JSONObject form; + try { + form = req.getSubmittedForm(); + } catch (ServletException ex) { + Logger.getLogger(DiskUsageProjectActionFactory.class.getName()).log(Level.SEVERE, null, ex); + return false; } - else{ - builder.append(", "); + //workspaceTimeOut = form.getInt("countInterval"); + checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnSlave"); + configureBuildsCalculation(form); + configureJobsCalculation(form); + configureWorkspacesCalculation(form); + String excluded = form.getString("excludedJobs"); + excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); + if(form.containsKey("warnings")) { + JSONObject warnings = form.getJSONObject("warnings"); + email = warnings.getString("email"); + if(email != null) { + allJobsSize = warnings.containsKey("jobsWarning") ? (warnings.getJSONObject("jobsWarning").getInt("allJobsSize") + " " + warnings.getJSONObject("jobsWarning").getString("JobsSizeUnit")) : null; + buildSize = warnings.containsKey("buildWarning") ? (warnings.getJSONObject("buildWarning").getInt("buildSize") + " " + warnings.getJSONObject("buildWarning").getString("buildSizeUnit")) : null; + jobSize = warnings.containsKey("jobWarning") ? (warnings.getJSONObject("jobWarning").getInt("jobSize") + " " + warnings.getJSONObject("jobWarning").getString("jobSizeUnit")) : null; + jobWorkspaceExceedSize = warnings.containsKey("workspaceWarning") ? (warnings.getJSONObject("workspaceWarning").getInt("jobWorkspaceExceedSize") + " " + warnings.getJSONObject("workspaceWarning").getString("jobWorkspaceExceedSizeUnit")) : null; + } } - builder.append(name); + showGraph = form.getBoolean("showGraph"); + String histlen = req.getParameter("historyLength"); + if(histlen != null && !histlen.isEmpty()) { + historyLength = Integer.parseInt(histlen); + } + timeoutWorkspace = form.getInt("timeoutWorkspace"); + showFreeSpaceForJobDirectory = form.getBoolean("showFreeSpaceForJobDirectory"); + save(); + return true; } - return builder.toString(); - } - - private void configureBuildsCalculation(JSONObject form){ - boolean oldCalculationBuilds = calculationBuilds; - String oldCountIntervalBuilds = countIntervalBuilds; - calculationBuilds = form.containsKey("calculationBuilds"); - countIntervalBuilds = calculationBuilds? form.getJSONObject("calculationBuilds").getString("countIntervalBuilds") : "0 */6 * * *"; - BuildDiskUsageCalculationThread buildCalculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); - if(!oldCountIntervalBuilds.equals(countIntervalBuilds) || oldCalculationBuilds != calculationBuilds) { - buildCalculation.reschedule(); + + public void onRenameJob(String oldName, String newName) { + if(excludedJobs.contains(oldName)) { + excludedJobs.remove(oldName); + excludedJobs.add(newName); + } } - } - - private void configureJobsCalculation(JSONObject form){ - boolean oldCalculationJobs = calculationJobs; - String oldcountIntervalJobs = countIntervalJobs; - calculationJobs = form.containsKey("calculationJobs"); - countIntervalJobs = calculationJobs? form.getJSONObject("calculationJobs").getString("countIntervalJobs") : "0 */6 * * *"; - JobWithoutBuildsDiskUsageCalculation jobCalculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); - if(!oldcountIntervalJobs.equals(countIntervalJobs) || oldCalculationJobs != calculationJobs) { - jobCalculation.reschedule(); + + public void onDeleteJob(AbstractProject project) { + String name = project.getName(); + if(excludedJobs.contains(name)) { + excludedJobs.remove(name); + } } - } - - private void configureWorkspacesCalculation(JSONObject form){ - boolean oldCalculationWorkspace = calculationWorkspace; - String oldCountIntervalWorkspace = countIntervalWorkspace; - calculationWorkspace = form.containsKey("calculationWorkspace"); - countIntervalWorkspace = calculationWorkspace? form.getJSONObject("calculationWorkspace").getString("countIntervalWorkspace") : "0 */6 * * *"; - WorkspaceDiskUsageCalculationThread workspaceCalculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); - if(!oldCountIntervalWorkspace.equals(countIntervalWorkspace) || oldCalculationWorkspace != calculationWorkspace) { - workspaceCalculation.reschedule(); + + public boolean isExcluded(AbstractProject project) { + return excludedJobs.contains(project.getName()); } - } - public int getTimeoutWorkspace() { - return timeoutWorkspace; - } - - public boolean getShowFreeSpaceForJobDirectory(){ - return showFreeSpaceForJobDirectory; - } + public String getExcludedJobsInString() { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for(String name: excludedJobs) { + if(first) { + first = false; + } + else { + builder.append(", "); + } + builder.append(name); + } + return builder.toString(); + } - public void setTimeoutWorkspace(Integer timeoutWorkspace) { - this.timeoutWorkspace = timeoutWorkspace; + private void configureBuildsCalculation(JSONObject form) { + boolean oldCalculationBuilds = calculationBuilds; + String oldCountIntervalBuilds = countIntervalBuilds; + calculationBuilds = form.containsKey("calculationBuilds"); + countIntervalBuilds = calculationBuilds ? form.getJSONObject("calculationBuilds").getString("countIntervalBuilds") : "0 */6 * * *"; + BuildDiskUsageCalculationThread buildCalculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); + if(!oldCountIntervalBuilds.equals(countIntervalBuilds) || oldCalculationBuilds != calculationBuilds) { + buildCalculation.reschedule(); + } + } + + private void configureJobsCalculation(JSONObject form) { + boolean oldCalculationJobs = calculationJobs; + String oldcountIntervalJobs = countIntervalJobs; + calculationJobs = form.containsKey("calculationJobs"); + countIntervalJobs = calculationJobs ? form.getJSONObject("calculationJobs").getString("countIntervalJobs") : "0 */6 * * *"; + JobWithoutBuildsDiskUsageCalculation jobCalculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); + if(!oldcountIntervalJobs.equals(countIntervalJobs) || oldCalculationJobs != calculationJobs) { + jobCalculation.reschedule(); + } + } + + private void configureWorkspacesCalculation(JSONObject form) { + boolean oldCalculationWorkspace = calculationWorkspace; + String oldCountIntervalWorkspace = countIntervalWorkspace; + calculationWorkspace = form.containsKey("calculationWorkspace"); + countIntervalWorkspace = calculationWorkspace ? form.getJSONObject("calculationWorkspace").getString("countIntervalWorkspace") : "0 */6 * * *"; + WorkspaceDiskUsageCalculationThread workspaceCalculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); + if(!oldCountIntervalWorkspace.equals(countIntervalWorkspace) || oldCalculationWorkspace != calculationWorkspace) { + workspaceCalculation.reschedule(); + } + } + + public int getTimeoutWorkspace() { + return timeoutWorkspace; + } + + public boolean getShowFreeSpaceForJobDirectory() { + return showFreeSpaceForJobDirectory; + } + + public void setTimeoutWorkspace(Integer timeoutWorkspace) { + this.timeoutWorkspace = timeoutWorkspace; + } } -} } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 18063204..71a93d43 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -34,133 +34,133 @@ public class DiskUsageProperty extends JobProperty> { public Collection getJobActions(Job job) { return Collections.emptyList(); } - - private transient ProjectDiskUsage diskUsage = new ProjectDiskUsage(); - @Deprecated - private Long diskUsageWithoutBuilds; - @Deprecated - private Map> slaveWorkspacesUsage; - - public void setDiskUsageWithoutBuilds(Long diskUsageWithoutBuilds){ - if(diskUsage==null){ - diskUsage = new ProjectDiskUsage(); + + private transient ProjectDiskUsage diskUsage = new ProjectDiskUsage(); + @Deprecated + private Long diskUsageWithoutBuilds; + @Deprecated + private Map> slaveWorkspacesUsage; + + public void setDiskUsageWithoutBuilds(Long diskUsageWithoutBuilds) { + if(diskUsage == null) { + diskUsage = new ProjectDiskUsage(); + } + diskUsage.load(); + this.diskUsage.diskUsageWithoutBuilds = diskUsageWithoutBuilds; + saveDiskUsage(); + } + + + public void remove(Node node, String path) { + Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + workspacesInfo.remove(path); + if(workspacesInfo.isEmpty()) { + getSlaveWorkspaceUsage().remove(node.getNodeName()); + } + saveDiskUsage(); + } + + public Set getDiskUsageOfBuilds() { + return diskUsage.getBuildDiskUsage(false); + } + + public Long getDiskUsageOfBuild(String buildId) { + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { + if(buildId.equals(information.getId())) { + return information.getSize(); } - diskUsage.load(); - this.diskUsage.diskUsageWithoutBuilds = diskUsageWithoutBuilds; - saveDiskUsage(); - } - - - public void remove(Node node, String path){ - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); - workspacesInfo.remove(path); - if(workspacesInfo.isEmpty()){ - getSlaveWorkspaceUsage().remove(node.getNodeName()); - } - saveDiskUsage(); - } - - public Set getDiskUsageOfBuilds(){ - return diskUsage.getBuildDiskUsage(false); - } - - public Long getDiskUsageOfBuild(String buildId){ - for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)){ - if(buildId.equals(information.getId())){ - return information.getSize(); - } - } - return 0L; - } - - public DiskUsageBuildInformation getDiskUsageBuildInformation(String buildId){ - for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)){ - if(buildId.equals(information.getId())){ - return information; - } - } - return null; - } - - public Long getAllDiskUsageOfBuild(String buildId){ - return getAllDiskUsageOfBuild(getDiskUsageBuildInformation(buildId).getNumber()); - } - - public Long getAllDiskUsageOfBuild(int buildNumber){ - Long size = getDiskUsageOfBuild(buildNumber); - if(owner instanceof ItemGroup){ - ItemGroup group = (ItemGroup) owner; - for(Object item : group.getItems()){ - if(item instanceof AbstractProject){ - AbstractProject project = (AbstractProject) item; - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - size += property.getAllDiskUsageOfBuild(buildNumber); - } - } - } - return size; - } - - - public DiskUsageBuildInformation getDiskUsageBuildInformation(int buildNumber){ - for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)){ - if(buildNumber == information.getNumber()){ - return information; - } - } - return null; - } - - public Long getDiskUsageOfBuild(int buildNumber){ - for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)){ - if(buildNumber == information.getNumber()){ - return information.getSize(); - } - } - return 0L; - } - - public ProjectDiskUsage getProjectDiskUsage(){ - return diskUsage; - } - - public ProjectDiskUsage getDiskUsage(){ - return diskUsage; - } - + } + return 0L; + } + + public DiskUsageBuildInformation getDiskUsageBuildInformation(String buildId) { + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { + if(buildId.equals(information.getId())) { + return information; + } + } + return null; + } + + public Long getAllDiskUsageOfBuild(String buildId) { + return getAllDiskUsageOfBuild(getDiskUsageBuildInformation(buildId).getNumber()); + } + + public Long getAllDiskUsageOfBuild(int buildNumber) { + Long size = getDiskUsageOfBuild(buildNumber); + if(owner instanceof ItemGroup) { + ItemGroup group = (ItemGroup) owner; + for(Object item: group.getItems()) { + if(item instanceof AbstractProject) { + AbstractProject project = (AbstractProject) item; + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + size += property.getAllDiskUsageOfBuild(buildNumber); + } + } + } + return size; + } + + + public DiskUsageBuildInformation getDiskUsageBuildInformation(int buildNumber) { + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { + if(buildNumber == information.getNumber()) { + return information; + } + } + return null; + } + + public Long getDiskUsageOfBuild(int buildNumber) { + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { + if(buildNumber == information.getNumber()) { + return information.getSize(); + } + } + return 0L; + } + + public ProjectDiskUsage getProjectDiskUsage() { + return diskUsage; + } + + public ProjectDiskUsage getDiskUsage() { + return diskUsage; + } + @Override - public void setOwner(Job job){ - super.setOwner(job); - diskUsage = new ProjectDiskUsage(); - diskUsage.setProject(job); - loadDiskUsage(); - //transfer old data - boolean modified = false; - if(diskUsageWithoutBuilds!=null){ - diskUsage.diskUsageWithoutBuilds = diskUsageWithoutBuilds; - diskUsageWithoutBuilds = null; - modified = true; - } - if(slaveWorkspacesUsage!=null){ - diskUsage.slaveWorkspacesUsage.putAll(slaveWorkspacesUsage); - slaveWorkspacesUsage = null; - modified = true; - } - if(modified){ - saveDiskUsage(); - try{ + public void setOwner(Job job) { + super.setOwner(job); + diskUsage = new ProjectDiskUsage(); + diskUsage.setProject(job); + loadDiskUsage(); + //transfer old data + boolean modified = false; + if(diskUsageWithoutBuilds != null) { + diskUsage.diskUsageWithoutBuilds = diskUsageWithoutBuilds; + diskUsageWithoutBuilds = null; + modified = true; + } + if(slaveWorkspacesUsage != null) { + diskUsage.slaveWorkspacesUsage.putAll(slaveWorkspacesUsage); + slaveWorkspacesUsage = null; + modified = true; + } + if(modified) { + saveDiskUsage(); + try { job.save(); - } - catch(Exception e){ - Logger.getLogger(getClass().getName()).log(Level.WARNING, "configuration of project " + job.getDisplayName() + " can not be saved.", e); - } - } - } - - public void putSlaveWorkspace(Node node, String path){ - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); - if(workspacesInfo==null){ - workspacesInfo = new ConcurrentHashMap(); + } + catch (Exception e) { + Logger.getLogger(getClass().getName()).log(Level.WARNING, "configuration of project " + job.getDisplayName() + " can not be saved.", e); + } + } + } + + public void putSlaveWorkspace(Node node, String path) { + Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); } if(!workspacesInfo.containsKey(path)) { workspacesInfo.put(path, 0l); @@ -169,16 +169,16 @@ public void putSlaveWorkspace(Node node, String path){ saveDiskUsage(); } - public Map> getSlaveWorkspaceUsage(){ - if(diskUsage.slaveWorkspacesUsage==null){ - // diskUsage.slaveWorkspacesUsage = new ConcurrentHashMap>(); - checkWorkspaces(); + public Map> getSlaveWorkspaceUsage() { + if(diskUsage.slaveWorkspacesUsage == null) { + // diskUsage.slaveWorkspacesUsage = new ConcurrentHashMap>(); + checkWorkspaces(); } return diskUsage.slaveWorkspacesUsage; } - public void putSlaveWorkspaceSize(Node node, String path, Long size){ - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + public void putSlaveWorkspaceSize(Node node, String path, Long size) { + Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap(); } @@ -186,46 +186,46 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size){ getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); } - - public Long getWorkspaceSize(Boolean containdedInWorkspace){ + + public Long getWorkspaceSize(Boolean containdedInWorkspace) { Long size = 0l; - for(String nodeName: getSlaveWorkspaceUsage().keySet()){ + for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node node = Jenkins.getInstance().getNode(nodeName); String workspacePath = null; - if(node instanceof Jenkins){ + if(node instanceof Jenkins) { workspacePath = Jenkins.getInstance().getRawWorkspaceDir(); } - if(node instanceof Slave){ + if(node instanceof Slave) { workspacePath = ((Slave) node).getRemoteFS(); } if(workspacePath == null) { continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()){ - if(containdedInWorkspace.equals(path.startsWith(workspacePath))){ + Map paths = getSlaveWorkspaceUsage().get(nodeName); + for(String path: paths.keySet()) { + if(containdedInWorkspace.equals(path.startsWith(workspacePath))) { size += paths.get(path); } } } return size; } - - private void checkAllBuilds(){ + + private void checkAllBuilds() { List builds = (List) owner.getBuilds(); - for(AbstractBuild build: builds){ - if(!build.isBuilding()){ + for(AbstractBuild build: builds) { + if(!build.isBuilding()) { Node node = build.getBuiltOn(); FilePath path = build.getWorkspace(); if(path == null) { continue; } - Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); - if(workspacesInfo==null){ - workspacesInfo = new ConcurrentHashMap(); + Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); workspacesInfo.put(path.getRemote(), 0L); } - else{ + else { if(!workspacesInfo.keySet().contains(path.getRemote())) { workspacesInfo.put(path.getRemote(), 0L); } @@ -234,24 +234,24 @@ private void checkAllBuilds(){ } } } - - private void checkLoadedBuilds(){ - if(owner instanceof AbstractProject){ + + private void checkLoadedBuilds() { + if(owner instanceof AbstractProject) { AbstractProject project = (AbstractProject) owner; Collection builds = project._getRuns().getLoadedBuilds().values(); - for(AbstractBuild build: builds){ - if(!build.isBuilding()){ + for(AbstractBuild build: builds) { + if(!build.isBuilding()) { Node node = build.getBuiltOn(); FilePath path = build.getWorkspace(); if(path == null) { continue; } - Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); - if(workspacesInfo==null){ - workspacesInfo = new ConcurrentHashMap(); + Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); + if(workspacesInfo == null) { + workspacesInfo = new ConcurrentHashMap(); workspacesInfo.put(path.getRemote(), 0L); } - else{ + else { if(!workspacesInfo.keySet().contains(path.getRemote())) { workspacesInfo.put(path.getRemote(), 0L); } @@ -261,139 +261,139 @@ private void checkLoadedBuilds(){ } } } - - public void checkWorkspaces(){ + + public void checkWorkspaces() { checkWorkspaces(false); } public void checkWorkspaces(boolean force) { - if(force){ - checkAllBuilds(); - } - else{ - checkLoadedBuilds(); - } - //only if it is wanted - can cost a quite long time to do it for all - if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnSlave() && owner instanceof TopLevelItem){ - for(Node node: Jenkins.getInstance().getNodes()){ - if(node.toComputer()!=null && node.toComputer().isOnline()){ - FilePath path =null; - try{ - path = node.getWorkspaceFor((TopLevelItem) owner); - if(path!=null && path.exists() && (diskUsage.slaveWorkspacesUsage.get(node.getNodeName())==null || !diskUsage.slaveWorkspacesUsage.get(node.getNodeName()).containsKey(path.getRemote()))){ - putSlaveWorkspace(node, path.getRemote()); - } - } - catch(Exception e){ - LOGGER.warning("Can not check if file " + path.getRemote() + " exists on node " + node.getNodeName()); + if(force) { + checkAllBuilds(); + } + else { + checkLoadedBuilds(); + } + //only if it is wanted - can cost a quite long time to do it for all + if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnSlave() && owner instanceof TopLevelItem) { + for(Node node: Jenkins.getInstance().getNodes()) { + if(node.toComputer() != null && node.toComputer().isOnline()) { + FilePath path = null; + try { + path = node.getWorkspaceFor((TopLevelItem) owner); + if(path != null && path.exists() && (diskUsage.slaveWorkspacesUsage.get(node.getNodeName()) == null || !diskUsage.slaveWorkspacesUsage.get(node.getNodeName()).containsKey(path.getRemote()))) { + putSlaveWorkspace(node, path.getRemote()); } } + catch (Exception e) { + LOGGER.warning("Can not check if file " + path.getRemote() + " exists on node " + node.getNodeName()); + } } } - - Iterator iterator = diskUsage.slaveWorkspacesUsage.keySet().iterator(); - while(iterator.hasNext()){ - String nodeName = iterator.next(); - Node node = Jenkins.getInstance().getNode(nodeName); - if(node == null && nodeName.isEmpty()) { - node = Jenkins.getInstance(); - } - //delete name of slaves which do not exist - if(node ==null) {//Jenkins master has empty name - iterator.remove(); - } - else{ - //delete path which does not exists - if(node!=null && node.toComputer()!=null && node.getChannel()!=null){ - Map workspaces = diskUsage.slaveWorkspacesUsage.get(nodeName); - Iterator pathIterator = workspaces.keySet().iterator(); - while(pathIterator.hasNext()){ - String path = pathIterator.next(); - try{ - FilePath workspace = node.createPath(path); - if(!workspace.exists()){ - pathIterator.remove(); - } - } - catch(Exception e){ - LOGGER.log(Level.WARNING, "Can not check if file " + path + " exists on node " + node.getNodeName()); + } + + Iterator iterator = diskUsage.slaveWorkspacesUsage.keySet().iterator(); + while(iterator.hasNext()) { + String nodeName = iterator.next(); + Node node = Jenkins.getInstance().getNode(nodeName); + if(node == null && nodeName.isEmpty()) { + node = Jenkins.getInstance(); + } + //delete name of slaves which do not exist + if(node == null) {//Jenkins master has empty name + iterator.remove(); + } + else { + //delete path which does not exists + if(node != null && node.toComputer() != null && node.getChannel() != null) { + Map workspaces = diskUsage.slaveWorkspacesUsage.get(nodeName); + Iterator pathIterator = workspaces.keySet().iterator(); + while(pathIterator.hasNext()) { + String path = pathIterator.next(); + try { + FilePath workspace = node.createPath(path); + if(!workspace.exists()) { + pathIterator.remove(); } } - if(workspaces.isEmpty()){ - iterator.remove(); + catch (Exception e) { + LOGGER.log(Level.WARNING, "Can not check if file " + path + " exists on node " + node.getNodeName()); } } + if(workspaces.isEmpty()) { + iterator.remove(); + } } } - saveDiskUsage(); + } + saveDiskUsage(); } - - public Long getAllNonSlaveOrCustomWorkspaceSize(){ + + public Long getAllNonSlaveOrCustomWorkspaceSize() { Long size = 0l; - for(String nodeName: getSlaveWorkspaceUsage().keySet()){ - Node node = null; - if(nodeName.isEmpty()){ + for(String nodeName: getSlaveWorkspaceUsage().keySet()) { + Node node = null; + if(nodeName.isEmpty()) { node = Jenkins.getInstance(); } - else{ + else { node = Jenkins.getInstance().getNode(nodeName); } if(node == null) { //slave does not exist continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()){ + Map paths = getSlaveWorkspaceUsage().get(nodeName); + for(String path: paths.keySet()) { TopLevelItem item = null; - if(owner instanceof TopLevelItem){ + if(owner instanceof TopLevelItem) { item = (TopLevelItem) owner; } - else{ + else { item = (TopLevelItem) owner.getParent(); } - try{ - if(!isContainedInWorkspace(item, node, path)){ + try { + if(!isContainedInWorkspace(item, node, path)) { size += paths.get(path); } } - catch(Exception e){ + catch (Exception e) { LOGGER.log(Level.WARNING, "Can not get workspace for " + item.getDisplayName() + " on " + node.getDisplayName(), e); } } } return size; } - - private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path){ - if(node instanceof Slave){ + + private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path) { + if(node instanceof Slave) { Slave slave = (Slave) node; return path.contains(slave.getRemoteFS()); } - else{ - if(node instanceof Jenkins){ - FilePath file = Jenkins.getInstance().getWorkspaceFor(item); - return path.contains(file.getRemote()); + else { + if(node instanceof Jenkins) { + FilePath file = Jenkins.getInstance().getWorkspaceFor(item); + return path.contains(file.getRemote()); } - else{ - try{ + else { + try { return path.contains(node.getWorkspaceFor(item).getRemote()); } - catch(Exception e){ + catch (Exception e) { return false; } } } } - public Long getAllWorkspaceSize(){ + public Long getAllWorkspaceSize() { Long size = 0l; - for(String nodeName: getSlaveWorkspaceUsage().keySet()){ + for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node slave = Jenkins.getInstance().getNode(nodeName); - if(slave==null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {//slave does not exist + if(slave == null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {//slave does not exist continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()){ - size += paths.get(path); + Map paths = getSlaveWorkspaceUsage().get(nodeName); + for(String path: paths.keySet()) { + size += paths.get(path); } } return size; @@ -412,36 +412,36 @@ public Long getAllWorkspaceSize(){ // return this; // } - public Long getDiskUsageWithoutBuilds(){ - if(diskUsage.diskUsageWithoutBuilds==null){ - diskUsage.diskUsageWithoutBuilds=0l; + public Long getDiskUsageWithoutBuilds() { + if(diskUsage.diskUsageWithoutBuilds == null) { + diskUsage.diskUsageWithoutBuilds = 0l; } return diskUsage.diskUsageWithoutBuilds; } - public Long getAllDiskUsageWithoutBuilds(){ + public Long getAllDiskUsageWithoutBuilds() { if(diskUsage.diskUsageWithoutBuilds == null) { diskUsage.diskUsageWithoutBuilds = 0l; } - Long usage = diskUsage.diskUsageWithoutBuilds; - if(owner instanceof ItemGroup){ - ItemGroup group = (ItemGroup) owner; - usage += getDiskUsageWithoutBuildsAllSubItems(group); - } - return usage; + Long usage = diskUsage.diskUsageWithoutBuilds; + if(owner instanceof ItemGroup) { + ItemGroup group = (ItemGroup) owner; + usage += getDiskUsageWithoutBuildsAllSubItems(group); + } + return usage; } - private Long getDiskUsageWithoutBuildsAllSubItems(ItemGroup group){ + private Long getDiskUsageWithoutBuildsAllSubItems(ItemGroup group) { Long usage = 0l; - for(Object item: group.getItems()){ - if(item instanceof ItemGroup){ - ItemGroup subGroup = (ItemGroup) item; - usage += getDiskUsageWithoutBuildsAllSubItems(subGroup); + for(Object item: group.getItems()) { + if(item instanceof ItemGroup) { + ItemGroup subGroup = (ItemGroup) item; + usage += getDiskUsageWithoutBuildsAllSubItems(subGroup); } - if(item instanceof AbstractProject){ + if(item instanceof AbstractProject) { AbstractProject p = (AbstractProject) item; DiskUsageProperty property = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(property!=null){ + if(property != null) { usage += property.getDiskUsageWithoutBuilds(); } } @@ -452,30 +452,30 @@ private Long getDiskUsageWithoutBuildsAllSubItems(ItemGroup group){ @Initializer(after = InitMilestone.PLUGINS_STARTED) public static void transitionAuth() throws IOException { DiskUsageDescriptor that = (DiskUsageDescriptor) Hudson.getInstance().getDescriptor(DiskUsageProperty.class); - if(that == null){ + if(that == null) { LOGGER.warning("Cannot convert DiskUsageProjectActions, DiskUsageDescripto is null, check log for previous DI error, e.g. Guice errors."); return; } - if (!that.converted) { + if(!that.converted) { DiskUsageProjectActionFactory.DESCRIPTOR.setShowGraph(that.showGraph); that.converted = true; that.save(); DiskUsageProjectActionFactory.DESCRIPTOR.save(); } - } + } public void saveDiskUsage() { diskUsage.save(); } - - public void loadDiskUsage(){ + + public void loadDiskUsage() { AbstractProject job = (AbstractProject) owner; - diskUsage.load(); + diskUsage.load(); //ensure that build was not removed without calling listener - badly removed, or badly saved (without build.xml) - for(DiskUsageBuildInformation information : diskUsage.getBuildDiskUsage(false)){ - File buildsDirectory = new File(owner.getRootDir(),"builds"); - File build = new File(buildsDirectory,information.getId()); - if(!build.exists()){ + for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { + File buildsDirectory = new File(owner.getRootDir(), "builds"); + File build = new File(buildsDirectory, information.getId()); + if(!build.exists()) { diskUsage.removeBuild(information); } } @@ -505,7 +505,7 @@ public String getDisplayName() { return Messages.DisplayName(); } - public boolean showGraph(){ + public boolean showGraph() { return showGraph; } @@ -514,6 +514,6 @@ public boolean isApplicable(Class jobType) { return true; } } - + public static final Logger LOGGER = Logger.getLogger(DiskUsageProperty.class.getName()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index bda736ff..35ea481b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -19,59 +19,59 @@ public class DiskUsageRecord { private Long allSpace = 0l; private Long diskUsageNonSlaveWorkspaces = 0l; - public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces){ - this.diskUsageBuilds = diskUsageBuilds; - this.diskUsageJobsWithoutBuilds = diskUsageJobsWithoutBuilds; - this.diskUsageWorkspaces = diskUsageWorkspaces; - this.allSpace = allSpace; - this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; - date = System.currentTimeMillis(); + public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { + this.diskUsageBuilds = diskUsageBuilds; + this.diskUsageJobsWithoutBuilds = diskUsageJobsWithoutBuilds; + this.diskUsageWorkspaces = diskUsageWorkspaces; + this.allSpace = allSpace; + this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; + date = System.currentTimeMillis(); } - public Long getBuildsDiskUsage(){ + public Long getBuildsDiskUsage() { if(diskUsageBuilds == null) { return 0l; } return diskUsageBuilds; } - - public Long getNonSlaveWorkspacesUsage(){ + + public Long getNonSlaveWorkspacesUsage() { return diskUsageNonSlaveWorkspaces; } - - public Long getSlaveWorkspacesUsage(){ + + public Long getSlaveWorkspacesUsage() { return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; } - public Long getJobsDiskUsage(){ + public Long getJobsDiskUsage() { if(diskUsageJobsWithoutBuilds == null) { return getBuildsDiskUsage(); } return diskUsageJobsWithoutBuilds + getBuildsDiskUsage(); } - public Long getAllSpace(){ + public Long getAllSpace() { if(allSpace == null) { return 0l; } return allSpace; } - public Long getWorkspacesDiskUsage(){ + public Long getWorkspacesDiskUsage() { if(diskUsageWorkspaces == null) { return 0l; } return diskUsageWorkspaces; } - Date getDate(){ + Date getDate() { final SimpleDateFormat sdf = new SimpleDateFormat("d/M"); - return new Date(date){ - private static final long serialVersionUID = 1L; - @Override - public String toString(){ - return sdf.format(this); - } - }; + return new Date(date){ + private static final long serialVersionUID = 1L; + @Override + public String toString() { + return sdf.format(this); + } + }; } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 903a0cdf..47dd9d5d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -47,53 +47,53 @@ * @author Lucie Votypkova */ public class DiskUsageUtil { - - public static void addProperty(Item item){ - if(item instanceof AbstractProject){ - AbstractProject project = (AbstractProject) item; + + public static void addProperty(Item item) { + if(item instanceof AbstractProject) { + AbstractProject project = (AbstractProject) item; + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + if(property == null) { + try { + property = new DiskUsageProperty(); + project.addProperty(property); + + } catch (IOException ex) { + Logger.getLogger(DiskUsageItemListener.class.getName()).log(Level.SEVERE, null, ex); + } + } + loadData(property, false); + } + if(item instanceof ItemGroup) { + + for(AbstractProject project: DiskUsageUtil.getAllProjects((ItemGroup) item)) { DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { try { property = new DiskUsageProperty(); project.addProperty(property); - } catch (IOException ex) { Logger.getLogger(DiskUsageItemListener.class.getName()).log(Level.SEVERE, null, ex); } } loadData(property, false); } - if(item instanceof ItemGroup){ - - for(AbstractProject project : DiskUsageUtil.getAllProjects((ItemGroup) item)){ - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ - try { - property = new DiskUsageProperty(); - project.addProperty(property); - } catch (IOException ex) { - Logger.getLogger(DiskUsageItemListener.class.getName()).log(Level.SEVERE, null, ex); - } - } - loadData(property, false); - } - } + } } - - protected static void loadData(DiskUsageProperty property, boolean loadAllBuilds){ - if(loadAllBuilds){ + + protected static void loadData(DiskUsageProperty property, boolean loadAllBuilds) { + if(loadAllBuilds) { try { property.getDiskUsage().loadAllBuilds(); } catch (IOException ex) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.SEVERE, null, ex); } } - else{ + else { property.loadDiskUsage(); } } - - public static Date getDate(String timeCount, String timeUnit){ + + public static Date getDate(String timeCount, String timeUnit) { if(timeUnit == null || !timeUnit.matches("\\d+") || !timeCount.matches("\\d+")) { return null; } @@ -101,42 +101,42 @@ public static Date getDate(String timeCount, String timeUnit){ int count = Integer.decode(timeCount); return getDate(unit, count); } - - public static Date getDate(int unit, int count){ + + public static Date getDate(int unit, int count) { Calendar calendar = new GregorianCalendar(); calendar.set(unit, calendar.get(unit) - count); return calendar.getTime(); } - - public static String formatTimeInMilisec(long time){ - if(time/1000<1){ + + public static String formatTimeInMilisec(long time) { + if(time / 1000 < 1) { return "0 seconds"; } - long inMinutes = time/60000; - long hours = inMinutes/60; + long inMinutes = time / 60000; + long hours = inMinutes / 60; String formatedTime = ""; - if(hours>0){ - String unit = hours>1? "hours" : "hour"; + if(hours > 0) { + String unit = hours > 1 ? "hours" : "hour"; formatedTime = hours + " " + unit; } - long minutes = inMinutes - hours*60; - if(minutes>0){ - String unit = minutes>1? "minutes" : "minute"; - formatedTime = formatedTime+ " " + minutes+ " " + unit; + long minutes = inMinutes - hours * 60; + if(minutes > 0) { + String unit = minutes > 1 ? "minutes" : "minute"; + formatedTime = formatedTime + " " + minutes + " " + unit; } - long seconds = (time/1000) - minutes*60 - hours*60*60; - if(seconds>0){ - String unit = minutes>1? "seconds" : "second"; - formatedTime = formatedTime+ " " + seconds+ " " + unit; + long seconds = (time / 1000) - minutes * 60 - hours * 60 * 60; + if(seconds > 0) { + String unit = minutes > 1 ? "seconds" : "second"; + formatedTime = formatedTime + " " + seconds + " " + unit; } return formatedTime; } - - public static void sendEmail(String subject, String message) throws MessagingException{ - + + public static void sendEmail(String subject, String message) throws MessagingException { + DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); String address = plugin.getConfiguration().getEmailAddress(); - if(address==null || address.isEmpty()){ + if(address == null || address.isEmpty()) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "e-mail addres is not set for notification about exceed disk size. Please set it in global configuration."); return; } @@ -146,35 +146,35 @@ public static void sendEmail(String subject, String message) throws MessagingExc msg.setFrom(new InternetAddress(Mailer.descriptor().getAdminAddress())); msg.setSentDate(new Date()); msg.setRecipient(RecipientType.TO, new InternetAddress(address)); - Transport.send(msg); + Transport.send(msg); } - - public static Long getSizeInBytes(String stringSize){ + + public static Long getSizeInBytes(String stringSize) { if(stringSize == null || "-".equals(stringSize)) { return 0l; } String[] values = stringSize.split(" "); int index = getIndex(values[1]); Long value = Long.decode(values[0]); - Double size = value * (Math.pow(1024, index)); - return Math.round(size); + Double size = value * (Math.pow(1024, index)); + return Math.round(size); } - - public static void controlAllJobsExceedSize() throws IOException{ + + public static void controlAllJobsExceedSize() throws IOException { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); plugin.refreshGlobalInformation(); Long allJobsSize = plugin.getCashedGlobalJobsDiskUsage(); Long exceedJobsSize = plugin.getConfiguration().getAllJobsExceedSize(); - if(allJobsSize>exceedJobsSize){ + if(allJobsSize > exceedJobsSize) { try { sendEmail("Jobs exeed size", "Jobs exceed size " + getSizeString(exceedJobsSize) + ". Their size is now " + getSizeString(allJobsSize)); } catch (MessagingException ex) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin can not send notification about exceeting build size.", ex); } - } + } } - - public static void controlWorkspaceExceedSize(AbstractProject project){ + + public static void controlWorkspaceExceedSize(AbstractProject project) { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -183,14 +183,14 @@ public static void controlWorkspaceExceedSize(AbstractProject project){ } Long size = property.getAllWorkspaceSize(); - if(plugin.getConfiguration().warnAboutJobWorkspaceExceedSize() && size>plugin.getConfiguration().getJobWorkspaceExceedSize()){ + if(plugin.getConfiguration().warnAboutJobWorkspaceExceedSize() && size > plugin.getConfiguration().getJobWorkspaceExceedSize()) { StringBuilder builder = new StringBuilder(); builder.append("Workspaces of Job " + project.getDisplayName() + " have size " + size + "."); builder.append("\n"); builder.append("List of workspaces:"); - for(String slaveName : property.getSlaveWorkspaceUsage().keySet()){ + for(String slaveName: property.getSlaveWorkspaceUsage().keySet()) { Long s = 0l; - for(Long l :property.getSlaveWorkspaceUsage().get(slaveName).values()){ + for(Long l:property.getSlaveWorkspaceUsage().get(slaveName).values()) { s += l; } builder.append("\n"); @@ -203,11 +203,11 @@ public static void controlWorkspaceExceedSize(AbstractProject project){ } } } - - public static List parseExcludedJobsFromString(String jobs){ + + public static List parseExcludedJobsFromString(String jobs) { List list = new ArrayList(); String[] jobNames = jobs.split(","); - for(String name: jobNames){ + for(String name: jobNames) { name = name.trim(); Item item = Jenkins.getInstance().getItem(name); if(item != null && item instanceof AbstractProject) { @@ -216,9 +216,9 @@ public static List parseExcludedJobsFromString(String jobs){ } return list; } - + public static String getSizeString(Long size) { - if (size == null || size <= 0) { + if(size == null || size <= 0) { return "-"; } @@ -236,8 +236,8 @@ public static double getScale(long number) { } return Math.floor(Math.log(number) / Math.log(1024)); } - - public static int getIndex(String unit){ + + public static int getIndex(String unit) { int index = 0; if("KB".equals(unit)) { index = 1; @@ -276,138 +276,138 @@ public static String getUnitString(int floor) { return unit; } - + /** * Calculate disk usage of build after its execution (or as post-build step) * @param build * @param listener */ - public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener listener){ - if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(build.getProject())){ + public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener listener) { + if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(build.getProject())) { listener.getLogger().println("This job is excluded from disk usage calculation."); return; } - try{ + try { //count build.xml too build.save(); DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); listener.getLogger().println("Started calculate disk usage of build"); Long startTimeOfBuildCalculation = System.currentTimeMillis(); - DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), build.getProject()); - listener.getLogger().println("Finished Calculation of disk usage of build in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfBuildCalculation)); - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - if(property==null){ - DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - } - if(build.getWorkspace()!=null){ - ArrayList exceededFiles = new ArrayList(); - AbstractProject project = build.getProject(); - Node node = build.getBuiltOn(); - if(project instanceof ItemGroup){ - List projects = DiskUsageUtil.getAllProjects((ItemGroup) project); - for(AbstractProject p: projects){ - DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(prop==null){ - prop = new DiskUsageProperty(); - p.addProperty(prop); - } - prop.checkWorkspaces(); - Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); - if(paths!=null && !paths.isEmpty()){ - for(String path: paths.keySet()){ - exceededFiles.add(new FilePath(node.getChannel(), path)); - } + DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), build.getProject()); + listener.getLogger().println("Finished Calculation of disk usage of build in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfBuildCalculation)); + DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + if(property == null) { + DiskUsageUtil.addProperty(build.getProject()); + property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + } + if(build.getWorkspace() != null) { + ArrayList exceededFiles = new ArrayList(); + AbstractProject project = build.getProject(); + Node node = build.getBuiltOn(); + if(project instanceof ItemGroup) { + List projects = DiskUsageUtil.getAllProjects((ItemGroup) project); + for(AbstractProject p: projects) { + DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); + if(prop == null) { + prop = new DiskUsageProperty(); + p.addProperty(prop); + } + prop.checkWorkspaces(); + Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); + if(paths != null && !paths.isEmpty()) { + for(String path: paths.keySet()) { + exceededFiles.add(new FilePath(node.getChannel(), path)); } } } - property.checkWorkspaces(); - listener.getLogger().println("Started calculate disk usage of workspace"); - Long startTimeOfWorkspaceCalculation = System.currentTimeMillis(); - Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(), exceededFiles); - listener.getLogger().println("Finished Calculation of disk usage of workspace in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfWorkspaceCalculation)); - property.putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); - property.saveDiskUsage(); - DiskUsageUtil.controlWorkspaceExceedSize(project); - property.saveDiskUsage(); } + property.checkWorkspaces(); + listener.getLogger().println("Started calculate disk usage of workspace"); + Long startTimeOfWorkspaceCalculation = System.currentTimeMillis(); + Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(), exceededFiles); + listener.getLogger().println("Finished Calculation of disk usage of workspace in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfWorkspaceCalculation)); + property.putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); + property.saveDiskUsage(); + DiskUsageUtil.controlWorkspaceExceedSize(project); + property.saveDiskUsage(); } - catch(Exception ex){ - listener.getLogger().println("Disk usage plugin fails during calculation disk usage of this build."); - Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin fails during build calculation disk space of job " + build.getParent().getDisplayName(), ex); - } + } + catch (Exception ex) { + listener.getLogger().println("Disk usage plugin fails during calculation disk usage of this build."); + Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin fails during build calculation disk space of job " + build.getParent().getDisplayName(), ex); + } } - - public static boolean isSymlink(File f) throws IOException{ + + public static boolean isSymlink(File f) throws IOException { return Util.isSymlink(f); } - + public static Long getFileSize(File f, List exceedFiles) throws IOException { - long size = 0; + long size = 0; if(!f.exists()) { return size; } - if (f.isDirectory() && !isSymlink(f)) { - File[] fileList = f.listFiles(); - if(fileList != null) { - for(File child: fileList) { - if(exceedFiles.contains(child)) { - continue; - } //do not count exceeded files - if(!isSymlink(child)) { - size += getFileSize(child, exceedFiles); - } + if(f.isDirectory() && !isSymlink(f)) { + File[] fileList = f.listFiles(); + if(fileList != null) { + for(File child: fileList) { + if(exceedFiles.contains(child)) { + continue; + } //do not count exceeded files + if(!isSymlink(child)) { + size += getFileSize(child, exceedFiles); } } - else { - LOGGER.info("Failed to list files in " + f.getPath() + " - ignoring"); - } } - return size + f.length(); - } - - public static void calculateDiskUsageForProject(AbstractProject project) throws IOException{ + else { + LOGGER.info("Failed to list files in " + f.getPath() + " - ignoring"); + } + } + return size + f.length(); + } + + public static void calculateDiskUsageForProject(AbstractProject project) throws IOException { if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; } DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - List exceededFiles = new ArrayList(); + List exceededFiles = new ArrayList(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } Set informations = (Set) property.getDiskUsage().getBuildDiskUsage(true); - for(DiskUsageBuildInformation information : informations){ + for(DiskUsageBuildInformation information: informations) { exceededFiles.add(new File(Jenkins.getInstance().getBuildDirFor(project), information.getId())); } - if(project instanceof ItemGroup){ + if(project instanceof ItemGroup) { List projects = getAllProjects((ItemGroup) project); - for(AbstractProject p: projects){ - exceededFiles.add(p.getRootDir()); + for(AbstractProject p: projects) { + exceededFiles.add(p.getRootDir()); } } long buildSize = DiskUsageUtil.getFileSize(project.getRootDir(), exceededFiles); Long diskUsageWithoutBuilds = property.getDiskUsageWithoutBuilds(); boolean update = false; - if (( diskUsageWithoutBuilds <= 0 ) || - ( Math.abs(diskUsageWithoutBuilds - buildSize) > 1024 )) { - property.setDiskUsageWithoutBuilds(buildSize); - update = true; - } - if(plugin.getConfiguration().warnAboutJobExceetedSize() && buildSize>plugin.getConfiguration().getJobExceedSize()){ + if((diskUsageWithoutBuilds <= 0) || + (Math.abs(diskUsageWithoutBuilds - buildSize) > 1024)) { + property.setDiskUsageWithoutBuilds(buildSize); + update = true; + } + if(plugin.getConfiguration().warnAboutJobExceetedSize() && buildSize > plugin.getConfiguration().getJobExceedSize()) { try { sendEmail("Job " + project.getDisplayName() + " exceeds size", "Job " + project.getDisplayName() + " has size " + getSizeString(buildSize) + "."); } catch (MessagingException ex) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin can not send notification about exceeting job size.", ex); } - } - if (update) { - property.saveDiskUsage(); } - } - - + if(update) { + property.saveDiskUsage(); + } + } + + // public static void addBuildDiskUsageAction(AbstractBuild build){ // BuildDiskUsageAction action = null; // for(Action a: build.getActions()){ @@ -425,12 +425,12 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws // } // } // } - public static void calculateDiskUsageForBuild(String buildId, AbstractProject project) - throws IOException { - if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { - return; - } - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + public static void calculateDiskUsageForBuild(String buildId, AbstractProject project) + throws IOException { + if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { + return; + } + DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); //Build disk usage has to be always recalculated to be kept up-to-date //- artifacts might be kept only for the last build and users sometimes delete files manually as well. long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList()); @@ -444,39 +444,39 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr // } Collection loadedBuilds = project._getRuns().getLoadedBuilds().values(); AbstractBuild build = null; - for(AbstractBuild b : loadedBuilds){ - if(b.getId().equals(buildId)){ + for(AbstractBuild b: loadedBuilds) { + if(b.getId().equals(buildId)) { build = b; break; //addBuildDiskUsageAction(build); } } DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(buildId); Long size = property.getDiskUsageOfBuild(buildId); - if (( size <= 0 ) || ( Math.abs(size - buildSize) > 1024 )) { - if(information!=null){ - information.setSize(buildSize); - } - else{ - if(build!=null){ - information = new DiskUsageBuildInformation(buildId, build.getTimeInMillis(), build.getNumber(), buildSize); - property.getDiskUsage().addBuildInformation(information, build); - } - else{ - //should not happen - AbstractBuild newLoadedBuild = (AbstractBuild) project._getRuns().getById(buildId); - information = new DiskUsageBuildInformation(buildId, newLoadedBuild.getTimeInMillis(), newLoadedBuild.getNumber(), buildSize); - property.getDiskUsage().addBuildInformation(information, build); - } - } - property.saveDiskUsage(); + if((size <= 0) || (Math.abs(size - buildSize) > 1024)) { + if(information != null) { + information.setSize(buildSize); + } + else { + if(build != null) { + information = new DiskUsageBuildInformation(buildId, build.getTimeInMillis(), build.getNumber(), buildSize); + property.getDiskUsage().addBuildInformation(information, build); + } + else { + //should not happen + AbstractBuild newLoadedBuild = (AbstractBuild) project._getRuns().getById(buildId); + information = new DiskUsageBuildInformation(buildId, newLoadedBuild.getTimeInMillis(), newLoadedBuild.getNumber(), buildSize); + property.getDiskUsage().addBuildInformation(information, build); + } + } + property.saveDiskUsage(); } - if(plugin.getConfiguration().warnAboutBuildExceetedSize() && buildSize>plugin.getConfiguration().getBuildExceedSize()){ + if(plugin.getConfiguration().warnAboutBuildExceetedSize() && buildSize > plugin.getConfiguration().getBuildExceedSize()) { try { sendEmail("Build with id " + information.getNumber() + " of project " + project.getDisplayName() + " exceeds size", "Build with id " + information.getNumber() + " of project " + project.getDisplayName() + " has size " + getSizeString(buildSize) + "."); } catch (MessagingException ex) { @@ -484,76 +484,76 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr } } } - - public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayList exceeded) throws IOException, InterruptedException{ + + public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayList exceeded) throws IOException, InterruptedException { Long diskUsage = 0l; - if(workspace.exists()){ - try{ - diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); + if(workspace.exists()) { + try { + diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); } - catch(Exception e){ + catch (Exception e) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage fails to calculate workspace for file path " + workspace.getRemote() + " through channel " + workspace.getChannel(), e); } } return diskUsage; } - + public static void calculateWorkspaceDiskUsage(AbstractProject project) throws IOException, InterruptedException { if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; } DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { addProperty(project); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); } - + property.checkWorkspaces(); - for(String nodeName: property.getSlaveWorkspaceUsage().keySet()){ + for(String nodeName: property.getSlaveWorkspaceUsage().keySet()) { Node node = null; - if(nodeName.isEmpty()){ + if(nodeName.isEmpty()) { node = Jenkins.getInstance(); } - else{ + else { node = Jenkins.getInstance().getNode(nodeName); } - if(node==null){ + if(node == null) { //probably does not exists yet continue; } - - if(node.toComputer()!=null && node.toComputer().getChannel()!=null){ + + if(node.toComputer() != null && node.toComputer().getChannel() != null) { Iterator iterator = property.getSlaveWorkspaceUsage().get(nodeName).keySet().iterator(); - while(iterator.hasNext()){ + while(iterator.hasNext()) { String projectWorkspace = iterator.next(); FilePath workspace = new FilePath(node.toComputer().getChannel(), projectWorkspace); - if(workspace.exists()){ + if(workspace.exists()) { Long diskUsage = property.getSlaveWorkspaceUsage().get(node.getNodeName()).get(workspace.getRemote()); ArrayList exceededFiles = new ArrayList(); - if(project instanceof ItemGroup){ + if(project instanceof ItemGroup) { List projects = getAllProjects((ItemGroup) project); - for(AbstractProject p: projects){ + for(AbstractProject p: projects) { DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(prop==null){ + if(prop == null) { prop = new DiskUsageProperty(); p.addProperty(prop); } prop.checkWorkspaces(); - Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); - if(paths!=null && !paths.isEmpty()){ - for(String path: paths.keySet()){ + Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); + if(paths != null && !paths.isEmpty()) { + for(String path: paths.keySet()) { exceededFiles.add(new FilePath(node.getChannel(), path)); } } } } diskUsage = calculateWorkspaceDiskUsageForPath(workspace, exceededFiles); - if(diskUsage!=null && diskUsage>0){ + if(diskUsage != null && diskUsage > 0) { property.putSlaveWorkspaceSize(node, workspace.getRemote(), diskUsage); } controlWorkspaceExceedSize(project); } - else{ + else { property.remove(node, projectWorkspace); } } @@ -561,14 +561,14 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I } property.saveDiskUsage(); } - + public static List getAllProjects(ItemGroup itemGroup) { List items = new ArrayList(); - for (Item item : itemGroup.getItems()) { - if(item instanceof AbstractProject){ + for(Item item: itemGroup.getItems()) { + if(item instanceof AbstractProject) { items.add((AbstractProject) item); } - if (item instanceof ItemGroup) { + if(item instanceof ItemGroup) { items.addAll(getAllProjects((ItemGroup) item)); } } @@ -580,8 +580,8 @@ public static List getAllProjects(ItemGroup ite */ public static class DiskUsageCallable implements Callable { - public static final Logger LOGGER = Logger - .getLogger(DiskUsageCallable.class.getName()); + public static final Logger LOGGER = Logger + .getLogger(DiskUsageCallable.class.getName()); private FilePath path; private List exceedFilesPath; @@ -594,7 +594,7 @@ public DiskUsageCallable(FilePath filePath, List exceedFilesPath) { public Long call() throws IOException { File f = new File(path.getRemote()); List exceeded = new ArrayList(); - for(FilePath file: exceedFilesPath){ + for(FilePath file: exceedFilesPath) { exceeded.add(new File(file.getRemote())); } return DiskUsageUtil.getFileSize(f, exceeded); @@ -602,10 +602,10 @@ public Long call() throws IOException { @Override public void checkRoles(RoleChecker rc) throws SecurityException { - + } - + } - + public static final Logger LOGGER = Logger.getLogger(DiskUsageUtil.class.getName()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java index 80bdf366..a2d18282 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java @@ -16,14 +16,14 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageWorkspaceListener extends WorkspaceListener{ - +public class DiskUsageWorkspaceListener extends WorkspaceListener { + @Override - public void afterDelete(AbstractProject project){ + public void afterDelete(AbstractProject project) { DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - if(property!=null){ + if(property != null) { property.checkWorkspaces(); } } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 21d37f2f..dbe499f7 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -23,63 +23,63 @@ * @author Lucie Votypkova */ @Extension -public class JobWithoutBuildsDiskUsageCalculation extends DiskUsageCalculation{ - +public class JobWithoutBuildsDiskUsageCalculation extends DiskUsageCalculation { + //last scheduled task; private static DiskUsageCalculation currentTask; - - - public JobWithoutBuildsDiskUsageCalculation(){ - super("Calculation of job directories (without builds)"); + + + public JobWithoutBuildsDiskUsageCalculation() { + super("Calculation of job directories (without builds)"); } @Override - public void execute(TaskListener listener) throws IOException, InterruptedException { + public void execute(TaskListener listener) throws IOException, InterruptedException { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(!isCancelled() && startExecution()){ - try{ + if(!isCancelled() && startExecution()) { + try { List items = new ArrayList(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); - for (Object item : items) { - if (item instanceof AbstractProject) { + for(Object item: items) { + if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; //do not count building project if(project.isBuilding()) { continue; } - try{ + try { DiskUsageUtil.calculateDiskUsageForProject(project); } catch (Exception ex) { logger.log(Level.WARNING, "Error when recording disk usage for " + project.getName(), ex); - } + } } } - if(plugin.getConfiguration().warnAboutAllJobsExceetedSize()){ + if(plugin.getConfiguration().warnAboutAllJobsExceetedSize()) { DiskUsageUtil.controlAllJobsExceedSize(); } } - catch(Exception e){ + catch (Exception e) { logger.log(Level.WARNING, "Error when recording disk usage for jobs.", e); } } - else{ - if(plugin.getConfiguration().isCalculationJobsEnabled()){ + else { + if(plugin.getConfiguration().isCalculationJobsEnabled()) { logger.log(Level.FINER, "Calculation of jobs is already in progress."); } - else{ + else { logger.log(Level.FINER, "Calculation of jobs is disabled."); } } } @Override - public AperiodicWork getNewInstance() { - if(currentTask!=null){ + public AperiodicWork getNewInstance() { + if(currentTask != null) { currentTask.cancel(); } - else{ + else { cancel(); } currentTask = new JobWithoutBuildsDiskUsageCalculation(); @@ -92,13 +92,13 @@ public CronTab getCronTab() throws ANTLRException { CronTab tab = new CronTab(cron); return tab; } - + @Override public DiskUsageCalculation getLastTask() { return currentTask; } - - private boolean startExecution(){ + + private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationJobsEnabled()) { return false; diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java b/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java index 925b6040..dc899d03 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java @@ -12,7 +12,7 @@ * @author Lucie Votypkova */ @Extension -public class ProjectConfigListener extends SaveableListener{ +public class ProjectConfigListener extends SaveableListener { + - } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index abd08fe8..add3120e 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -33,46 +33,46 @@ * * @author Lucie Votypkova */ -public class ProjectDiskUsage implements Saveable{ - +public class ProjectDiskUsage implements Saveable { + protected transient Job job; protected Long diskUsageWithoutBuilds = 0l; - protected Map> slaveWorkspacesUsage = new ConcurrentHashMap>(); + protected Map> slaveWorkspacesUsage = new ConcurrentHashMap>(); private Set buildDiskUsage = new CopyOnWriteArraySet(); private boolean allBuildsLoaded; - - - public Map> getSlaveWorkspacesUsage(){ + + + public Map> getSlaveWorkspacesUsage() { return Maps.newHashMap(slaveWorkspacesUsage); } - - public XmlFile getConfigFile(){ + + public XmlFile getConfigFile() { return new XmlFile(new File(job.getRootDir(), "disk-usage.xml")); } - - public void setProject(Job job){ - this.job = job; - } - - public boolean isBuildsLoaded(){ - return buildDiskUsage!=null; - } - - public Set getBuildDiskUsage(boolean needAll){ - Set information = new HashSet(); - AbstractProject p = (AbstractProject) job; - if(needAll && !allBuildsLoaded){ - try{ + + public void setProject(Job job) { + this.job = job; + } + + public boolean isBuildsLoaded() { + return buildDiskUsage != null; + } + + public Set getBuildDiskUsage(boolean needAll) { + Set information = new HashSet(); + AbstractProject p = (AbstractProject) job; + if(needAll && !allBuildsLoaded) { + try { loadAllBuilds(); - } - catch(Exception e){ - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load builds " + getConfigFile(), e); - } - } - information.addAll(buildDiskUsage); - return information; - } - + } + catch (Exception e) { + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load builds " + getConfigFile(), e); + } + } + information.addAll(buildDiskUsage); + return information; + } + public synchronized void save() { if(BulkChange.contains(this)) { return; @@ -85,79 +85,79 @@ public synchronized void save() { } } - - public void removeBuild(DiskUsageBuildInformation information){ + + public void removeBuild(DiskUsageBuildInformation information) { buildDiskUsage.remove(information); } - - private int numberOfBuildFolders() throws IOException{ + + private int numberOfBuildFolders() throws IOException { File file = job.getBuildDir(); int count = 0; - if(file!=null && file.exists() && file.isDirectory()){ - for(File f : file.listFiles()){ - if(!FileUtils.isSymlink(f) && !f.isDirectory()){ + if(file != null && file.exists() && file.isDirectory()) { + for(File f: file.listFiles()) { + if(!FileUtils.isSymlink(f) && !f.isDirectory()) { count++; } } } return count; } - - public void putSlaveWorkspaceSize(Node node, String path, Long size){ - Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); + + public void putSlaveWorkspaceSize(Node node, String path, Long size) { + Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap(); } //worksace with 0 are only initiative (are not counted yet) or does not exists //no nexist workspaces are removed in method checkWorkspaces in class DiskUsageProperty - if(workspacesInfo.get(path)==null || size>0l ){ + if(workspacesInfo.get(path) == null || size > 0l) { workspacesInfo.put(path, size); } slaveWorkspacesUsage.put(node.getNodeName(), workspacesInfo); } - - public boolean containsBuildWithId(String id){ - for(DiskUsageBuildInformation inf : buildDiskUsage){ - if(inf.getId().equals(id)){ + + public boolean containsBuildWithId(String id) { + for(DiskUsageBuildInformation inf: buildDiskUsage) { + if(inf.getId().equals(id)) { return true; } } return false; } - - public void loadAllBuilds() throws IOException{ + + public void loadAllBuilds() throws IOException { load(); int loadedBuildInformation = buildDiskUsage.size(); - if(loadedBuildInformation>=numberOfBuildFolders()){ + if(loadedBuildInformation >= numberOfBuildFolders()) { return; } AbstractProject project = (AbstractProject) job; List list = project.getBuilds(); buildDiskUsage = new CopyOnWriteArraySet(); - for(Run run : list){ - if(run instanceof AbstractBuild){ - if(containsBuildWithId(run.getId())){ + for(Run run: list) { + if(run instanceof AbstractBuild) { + if(containsBuildWithId(run.getId())) { continue; } AbstractBuild build = (AbstractBuild) run; BuildDiskUsageAction toRemove = null; long buildOldDiskUsage = 0l; //if not present, add - for(Action action : build.getActions()){ - if(action instanceof BuildDiskUsageAction){ - toRemove=(BuildDiskUsageAction) action; - buildOldDiskUsage = toRemove.buildDiskUsage; + for(Action action: build.getActions()) { + if(action instanceof BuildDiskUsageAction) { + toRemove = (BuildDiskUsageAction) action; + buildOldDiskUsage = toRemove.buildDiskUsage; } } - if(toRemove!=null){ + if(toRemove != null) { build.getActions().remove(toRemove); } - if(build.getWorkspace()!=null){ + if(build.getWorkspace() != null) { putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); addBuildInformation(information, build); - if(information.getSize()==0l){ + if(information.getSize() == 0l) { information.setSize(buildOldDiskUsage); } // if(usage==null){ @@ -168,8 +168,8 @@ public void loadAllBuilds() throws IOException{ // Logger.getLogger(ProjectDiskUsage.class.getName()).log(Level.SEVERE, null, ex); // } // } - // else{ - // } + // else{ + // } //DiskUsageUtil.addBuildDiskUsageAction(build); } } @@ -178,30 +178,30 @@ public void loadAllBuilds() throws IOException{ property.checkWorkspaces(true); save(); } - - public synchronized void load(){ - XmlFile file = getConfigFile(); - if(!file.getFile().exists()){ - return; - } - try { - file.unmarshal(this); - if(buildDiskUsage instanceof HashSet){ - //saved collection is not serialized in previous versions. - Set informations = new CopyOnWriteArraySet(); - informations.addAll(buildDiskUsage); - buildDiskUsage = informations; - } - } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load " + file, e); + + public synchronized void load() { + XmlFile file = getConfigFile(); + if(!file.getFile().exists()) { + return; + } + try { + file.unmarshal(this); + if(buildDiskUsage instanceof HashSet) { + //saved collection is not serialized in previous versions. + Set informations = new CopyOnWriteArraySet(); + informations.addAll(buildDiskUsage); + buildDiskUsage = informations; } + } catch (IOException e) { + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load " + file, e); + } // if(buildDiskUsage==null){ // //seems like it needs load old data // loadOldData(); // } // removeDeletedBuilds(); } - + /** * IT is only for backward compatibility to load old data. It breaks lazy loading. * Should be used only one times - updating of plugin @@ -209,16 +209,16 @@ public synchronized void load(){ * @deprecated * */ - public void loadOldData(){ + public void loadOldData() { buildDiskUsage = new CopyOnWriteArraySet(); List list = job.getBuilds(); - for(Run run : list){ - if(run instanceof AbstractBuild){ + for(Run run: list) { + if(run instanceof AbstractBuild) { AbstractBuild build = (AbstractBuild) run; BuildDiskUsageAction usage = run.getAction(BuildDiskUsageAction.class); DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); - addBuildInformation(information, build); - if(usage!=null){ + addBuildInformation(information, build); + if(usage != null) { information.setSize(usage.buildDiskUsage); run.getAllActions().remove(usage); } @@ -226,29 +226,29 @@ public void loadOldData(){ } save(); } - - public DiskUsageBuildInformation getDiskUsageBuildInformation(int number){ - for(DiskUsageBuildInformation information : buildDiskUsage){ - if(information.getNumber()==number){ + + public DiskUsageBuildInformation getDiskUsageBuildInformation(int number) { + for(DiskUsageBuildInformation information: buildDiskUsage) { + if(information.getNumber() == number) { return information; } } return null; } - - public void addBuildInformation(DiskUsageBuildInformation info, AbstractBuild build){ - if(!containsBuildWithId(info.getId())){ - buildDiskUsage.add(info); - if(build!=null && build.getWorkspace()!=null){ + + public void addBuildInformation(DiskUsageBuildInformation info, AbstractBuild build) { + if(!containsBuildWithId(info.getId())) { + buildDiskUsage.add(info); + if(build != null && build.getWorkspace() != null) { putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } } } - - private void removeDeletedBuilds(){ - - Iterator iterator= buildDiskUsage.iterator(); - while(iterator.hasNext()){ + + private void removeDeletedBuilds() { + + Iterator iterator = buildDiskUsage.iterator(); + while(iterator.hasNext()) { DiskUsageBuildInformation information = iterator.next(); File buildDir = new File(Jenkins.getInstance().getBuildDirFor(job), information.getId()); if(!buildDir.exists()) { diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 3f5fc661..c8a8f6a7 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -31,106 +31,106 @@ public class ProjectDiskUsageAction implements ProminentProjectAction { AbstractProject project; - + public ProjectDiskUsageAction(AbstractProject project) { - this.project = project; + this.project = project; } - - public String getIconFileName() { + + public String getIconFileName() { return null; } - - public String getDisplayName() { + + public String getDisplayName() { return Messages.DisplayName(); } public String getUrlName() { return Messages.UrlName(); } - - public Long getDiskUsageWorkspace(){ + + public Long getDiskUsageWorkspace() { DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } return property.getAllWorkspaceSize(); } - - public Long getAllSlaveWorkspaces(){ + + public Long getAllSlaveWorkspaces() { return getAllDiskUsageWorkspace() - getAllCustomOrNonSlaveWorkspaces(); } - - public Long getAllCustomOrNonSlaveWorkspaces(){ + + public Long getAllCustomOrNonSlaveWorkspaces() { Long diskUsage = 0l; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property!=null){ + if(property != null) { diskUsage += property.getAllNonSlaveOrCustomWorkspaceSize(); } - if(project instanceof ItemGroup){ + if(project instanceof ItemGroup) { ItemGroup group = (ItemGroup) project; - for(Object i:group.getItems()){ - if(i instanceof AbstractProject){ + for(Object i:group.getItems()) { + if(i instanceof AbstractProject) { AbstractProject p = (AbstractProject) i; DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(prop!=null){ + if(prop != null) { diskUsage += prop.getAllNonSlaveOrCustomWorkspaceSize(); - } + } } } } return diskUsage; } - + /** * Returns all workspace disku usage including workspace usage its sub-projects * * @return disk usage project and its sub-projects */ - public Long getAllDiskUsageWorkspace(){ + public Long getAllDiskUsageWorkspace() { Long diskUsage = 0l; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property!=null){ + if(property != null) { diskUsage += property.getAllWorkspaceSize(); } - if(project instanceof ItemGroup){ + if(project instanceof ItemGroup) { ItemGroup group = (ItemGroup) project; - for(Object i:group.getItems()){ - if(i instanceof AbstractProject){ + for(Object i:group.getItems()) { + if(i instanceof AbstractProject) { AbstractProject p = (AbstractProject) i; DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(prop!=null){ + if(prop != null) { diskUsage += prop.getAllWorkspaceSize(); - } + } } } } return diskUsage; } - - public String getSizeInString(Long size){ - return DiskUsageUtil.getSizeString(size); + + public String getSizeInString(Long size) { + return DiskUsageUtil.getSizeString(size); } - - public Long getDiskUsageWithoutBuilds(){ + + public Long getDiskUsageWithoutBuilds() { DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } return property.getDiskUsageWithoutBuilds(); } - - public Long getAllDiskUsageWithoutBuilds(){ + + public Long getAllDiskUsageWithoutBuilds() { DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } return property.getAllDiskUsageWithoutBuilds(); } - - + + public Long getJobRootDirDiskUsage() { try { return getBuildsDiskUsage().get("all") + getDiskUsageWithoutBuilds(); @@ -139,29 +139,29 @@ public Long getJobRootDirDiskUsage() { return 0L; } } - - private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date older, Date yonger) throws IOException{ - Map diskUsage = new TreeMap(); + + private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date older, Date yonger) throws IOException { + Map diskUsage = new TreeMap(); Long buildsDiskUsage = 0l; Long locked = 0l; Long notLoaded = 0L; - for(Object item: group.getItems()){ - if(item instanceof ItemGroup){ - ItemGroup subGroup = (ItemGroup) item; - buildsDiskUsage += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("all"); - locked += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("locked"); - notLoaded += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("notLoaded"); + for(Object item: group.getItems()) { + if(item instanceof ItemGroup) { + ItemGroup subGroup = (ItemGroup) item; + buildsDiskUsage += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("all"); + locked += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("locked"); + notLoaded += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("notLoaded"); } - else{ - if(group instanceof AbstractProject){ + else { + if(group instanceof AbstractProject) { AbstractProject p = (AbstractProject) item; DiskUsageProperty property = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } Set informations = property.getDiskUsageOfBuilds(); - for(DiskUsageBuildInformation information: informations){ + for(DiskUsageBuildInformation information: informations) { Date date = new Date(information.getTimestamp()); if(older != null && !date.before(older)) { continue; @@ -173,105 +173,105 @@ private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date old buildsDiskUsage += size; Collection loadedBuilds = (Collection) p._getRuns().getLoadedBuilds().values(); AbstractBuild build = null; - for (AbstractBuild b : loadedBuilds){ - if(b.getId().equals(information.getId())){ + for(AbstractBuild b: loadedBuilds) { + if(b.getId().equals(information.getId())) { build = b; } } - if(build!=null){ - if(build.isKeepLog()){ + if(build != null) { + if(build.isKeepLog()) { locked += size; } } - else{ + else { notLoaded += size; } } } } - + } diskUsage.put("all", buildsDiskUsage); diskUsage.put("locked", locked); diskUsage.put("notLoaded", notLoaded); return diskUsage; } - + public Map getBuildsDiskUsage() throws IOException { return getBuildsDiskUsage(null, null); } - - public Long getAllBuildsDiskUsage() throws IOException{ + + public Long getAllBuildsDiskUsage() throws IOException { return getBuildsDiskUsage(null, null).get("all"); } - + /** * @return Disk usage for all builds */ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOException { DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } - Map diskUsage = new TreeMap(); + Map diskUsage = new TreeMap(); Long buildsDiskUsage = 0l; Long locked = 0l; Long notLoaded = 0l; - if (project != null) { - if(project instanceof ItemGroup){ - ItemGroup group = (ItemGroup) project; - Map sizes = getBuildsDiskUsageAllSubItems(group, older, yonger); - buildsDiskUsage += sizes.get("all"); - locked += sizes.get("locked"); - notLoaded += sizes.get("notLoaded"); + if(project != null) { + if(project instanceof ItemGroup) { + ItemGroup group = (ItemGroup) project; + Map sizes = getBuildsDiskUsageAllSubItems(group, older, yonger); + buildsDiskUsage += sizes.get("all"); + locked += sizes.get("locked"); + notLoaded += sizes.get("notLoaded"); } - Set informations = property.getDiskUsageOfBuilds(); - for(DiskUsageBuildInformation information: informations){ - Date date = new Date(information.getTimestamp()); - if(older != null && !date.before(older)) { - continue; - } - if(yonger != null && !date.after(yonger)) { - continue; - } - Long size = information.getSize(); - buildsDiskUsage += size; - Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); - AbstractBuild build = null; - for (AbstractBuild b : loadedBuilds){ - if(b.getId().equals(information.getId())){ - build = b; + Set informations = property.getDiskUsageOfBuilds(); + for(DiskUsageBuildInformation information: informations) { + Date date = new Date(information.getTimestamp()); + if(older != null && !date.before(older)) { + continue; } - } - if(build!=null){ - if(build.isKeepLog()){ - locked += size; + if(yonger != null && !date.after(yonger)) { + continue; + } + Long size = information.getSize(); + buildsDiskUsage += size; + Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); + AbstractBuild build = null; + for(AbstractBuild b: loadedBuilds) { + if(b.getId().equals(information.getId())) { + build = b; + } + } + if(build != null) { + if(build.isKeepLog()) { + locked += size; + } + } + else { + notLoaded += size; } } - else{ - notLoaded += size; - } - } } diskUsage.put("all", buildsDiskUsage); diskUsage.put("locked", locked); diskUsage.put("notLoaded", notLoaded); return diskUsage; } - + public BuildDiskUsageAction getLastBuildAction() { Run run = project.getLastBuild(); - if (run != null) { + if(run != null) { return run.getAction(BuildDiskUsageAction.class); } return null; } - - public Set getBuildsInformation() throws IOException{ + + public Set getBuildsInformation() throws IOException { DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } @@ -298,8 +298,8 @@ public Graph getGraph() throws IOException { for(int i = builds.size() - 1; i >= 0; i--) { DiskUsageBuildInformation build = builds.get(i); Long diskUsage = property.getDiskUsageOfBuild(build.getId()); - usages.add(new Object[]{build.getNumber(), getJobRootDirDiskUsage(), diskUsage, getAllSlaveWorkspaces(), getAllCustomOrNonSlaveWorkspaces()}); - maxValue = Math.max(maxValue, diskUsage); + usages.add(new Object[]{build.getNumber(), getJobRootDirDiskUsage(), diskUsage, getAllSlaveWorkspaces(), getAllCustomOrNonSlaveWorkspaces()}); + maxValue = Math.max(maxValue, diskUsage); } int floor = (int) DiskUsageUtil.getScale(maxValue); @@ -310,16 +310,16 @@ public Graph getGraph() throws IOException { double workspaceBase = Math.pow(1024, workspaceFloor); DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset dataset2 = new DefaultCategoryDataset(); - for (Object[] usage : usages) { + for(Object[] usage: usages) { Integer label = (Integer) usage[0]; dataset.addValue(((Long) usage[1]) / base, - Messages.DiskUsage_Graph_JobDirectory(), label); + Messages.DiskUsage_Graph_JobDirectory(), label); dataset.addValue(((Long) usage[2]) / base, - Messages.DiskUsage_Graph_BuildDirectory(), label); + Messages.DiskUsage_Graph_BuildDirectory(), label); dataset2.addValue(((Long) usage[3]) / workspaceBase, - Messages.DiskUsage_Graph_SlaveWorkspaces(), label); + Messages.DiskUsage_Graph_SlaveWorkspaces(), label); dataset2.addValue(((Long) usage[4]) / workspaceBase, - Messages.DiskUsage_Graph_NonSlaveWorkspaces(), label); + Messages.DiskUsage_Graph_NonSlaveWorkspaces(), label); } return new DiskUsageGraph(dataset, unit, dataset2, workspaceUnit); } diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 2079a752..e3d04e54 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -23,59 +23,59 @@ * @author Lucie Votypkova */ @Extension -public class WorkspaceDiskUsageCalculationThread extends DiskUsageCalculation{ - +public class WorkspaceDiskUsageCalculationThread extends DiskUsageCalculation { + //last scheduled task; - private static DiskUsageCalculation currentTask; - - public WorkspaceDiskUsageCalculationThread(){ - super("Calculation of workspace usage"); - } + private static DiskUsageCalculation currentTask; + + public WorkspaceDiskUsageCalculationThread() { + super("Calculation of workspace usage"); + } @Override - public void execute(TaskListener listener) throws IOException, InterruptedException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - if(!isCancelled() && startExecution()){ - try{ + public void execute(TaskListener listener) throws IOException, InterruptedException { + DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + if(!isCancelled() && startExecution()) { + try { List items = new ArrayList(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); - for (Object item : items) { - if (item instanceof AbstractProject) { + for(Object item: items) { + if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; //do not count workspace for running project if(project.isBuilding()) { continue; } - try{ + try { DiskUsageUtil.calculateWorkspaceDiskUsage(project); } catch (Exception ex) { logger.log(Level.WARNING, "Error when recording disk usage for " + project.getName(), ex); - } + } } } } - catch(Exception e){ + catch (Exception e) { logger.log(Level.WARNING, "Error when recording disk usage for workspaces.", e); } } - else{ - if(plugin.getConfiguration().isCalculationWorkspaceEnabled()){ + else { + if(plugin.getConfiguration().isCalculationWorkspaceEnabled()) { logger.log(Level.FINER, "Calculation of workspace is already in progress."); } - else{ + else { logger.log(Level.FINER, "Calculation of workspace is disabled."); } } - - } - + + } + @Override - public AperiodicWork getNewInstance() { - if(currentTask!=null){ + public AperiodicWork getNewInstance() { + if(currentTask != null) { currentTask.cancel(); } - else{ + else { cancel(); } currentTask = new WorkspaceDiskUsageCalculationThread(); @@ -93,13 +93,13 @@ public CronTab getCronTab() throws ANTLRException { public DiskUsageCalculation getLastTask() { return currentTask; } - - private boolean startExecution(){ + + private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationWorkspaceEnabled()) { return false; } return !isExecutingMoreThenOneTimes(); } - + } diff --git a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java index 76b5ab1f..a9b82f86 100644 --- a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java @@ -21,26 +21,25 @@ * * @author lucinka */ -public class DiskUsagePostBuildCalculation extends Recorder{ - - public DiskUsagePostBuildCalculation(){ +public class DiskUsagePostBuildCalculation extends Recorder { + + public DiskUsagePostBuildCalculation() { } - + @Override - public boolean perform(Build build, Launcher launcher, BuildListener listener){ + public boolean perform(Build build, Launcher launcher, BuildListener listener) { listener.getLogger().println("append disk usage"); - DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); - return true; - } - - + DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); + return true; + } + @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } - - + + @Extension public static class DescriptorImpl extends BuildStepDescriptor { public String getDisplayName() { @@ -57,5 +56,5 @@ public boolean isApplicable(Class jobType) { return true; } } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index fcaff71b..8500091d 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -19,7 +19,7 @@ * * @author lucinka */ -public class DiskUsageCalculationTest extends TestCase{ +public class DiskUsageCalculationTest extends TestCase { /** * Depends on test testReschedule() - if testReshedule fails this test probably will fail too. @@ -27,14 +27,14 @@ public class DiskUsageCalculationTest extends TestCase{ * see @testReschedule() */ @Test - public void testScheduledExecutionTime() throws Exception{ - // Trigger.timer = new Timer("Jenkins cron thread"); // it should be enought there is no need to start Jenkins + public void testScheduledExecutionTime() throws Exception { + // Trigger.timer = new Timer("Jenkins cron thread"); // it should be enought there is no need to start Jenkins GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", false); - if(calculation.getLastTask()!=null){ + if(calculation.getLastTask() != null) { //should not be any, but if cancel; calculation.getLastTask().cancel(); } @@ -42,7 +42,7 @@ public void testScheduledExecutionTime() throws Exception{ assertEquals("Scheduled time of disk usage calculation should 0, because calculation is not scheduled", 0, calculation.scheduledLastInstanceExecutionTime(), 60000); Timer.get().schedule(calculation.getNewInstance(), calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); assertEquals("Scheduled time of disk usage calculation should be in 10 minutes", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); - + //scheduled time should be changed if configuration of cron is changed calendar.add(Calendar.MINUTE, 10); minute = calendar.get(Calendar.MINUTE); @@ -50,13 +50,13 @@ public void testScheduledExecutionTime() throws Exception{ calculation.reschedule(); expectedNextExecution = calendar.getTimeInMillis(); assertEquals("Scheduled time of disk usage calculation should be changed", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); - + } - + @Test - public void testGetRecurrencePeriod(){ + public void testGetRecurrencePeriod() { GregorianCalendar calendar = new GregorianCalendar(); - + //for minutes int minute = calendar.get(Calendar.MINUTE); minute = minute + 2; @@ -66,7 +66,7 @@ public void testGetRecurrencePeriod(){ Long period = calculation.getRecurrencePeriod(); Long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculation should be executed accurately in 2 minutes", expectedPeriod, period, 60000); - + //for hours calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); @@ -77,52 +77,52 @@ public void testGetRecurrencePeriod(){ period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 hours.", expectedPeriod, period, 60000); - + //for days calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, 2); int day = calendar.get(Calendar.DAY_OF_MONTH); calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *", false); - period = calculation.getRecurrencePeriod(); + period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 days.", expectedPeriod, period, 60000); - + //for months calendar = new GregorianCalendar(); calendar.add(Calendar.MONTH, 2); int month = calendar.get(Calendar.MONTH) + 1; //months are indexed from 0 calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + month + " *", false); - period = calculation.getRecurrencePeriod(); - expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); + period = calculation.getRecurrencePeriod(); + expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); - + //day of week calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_WEEK, 2); - int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) -1; + int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1; calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + (calendar.get(Calendar.MONTH) + 1) + " " + dayOfWeek, false); - period = calculation.getRecurrencePeriod(); - expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); + period = calculation.getRecurrencePeriod(); + expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); - + } - - + + /** * Depends on test testScheduledExecutionTime() - if testReshedule fails this test probably will fail too. * * see @testScheduledExecutionTime() */ @Test - public void testReschedule() throws Exception{ + public void testReschedule() throws Exception { //Trigger.timer = new Timer("Jenkins cron thread"); GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation - TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", true).getNewInstance(); + TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", true).getNewInstance(); Timer.get().schedule(calculation, calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); //schedule it; calendar.add(Calendar.MINUTE, 10); minute = calendar.get(Calendar.MINUTE); @@ -136,34 +136,33 @@ public void testReschedule() throws Exception{ // fail("Calculation should be canceled."); // } assertEquals("A new calculation should be scheduled with a new scheduled time.", calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000); - + } - + @Test - public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception{ - // Trigger.timer = new Timer("Jenkins cron thread"); + public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { + // Trigger.timer = new Timer("Jenkins cron thread"); // attribut currentTask should have value calculation List scheduledInstances = new ArrayList(); - TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); + TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); TestDiskUsageCalculation.startLoadInstancesHistory(scheduledInstances); GregorianCalendar calendar = new GregorianCalendar(); int seconds = calendar.get(Calendar.SECOND); boolean firstLoop = true; - while((seconds>55 && seconds<59) || seconds==0){ //have enought time for measure in current minute - if(firstLoop){ + while((seconds > 55 && seconds < 59) || seconds == 0) { //have enought time for measure in current minute + if(firstLoop) { System.out.println("Waiting for appropriate time "); firstLoop = false; - } - else{ + }else { System.out.println("."); } - Thread.sleep(1000); + Thread.sleep(1000); seconds = calendar.get(Calendar.SECOND); - } + } calculation.doRun(); Thread.sleep(2000); assertEquals("Method getRecurencePeriod should not able to schedule more than 1 task in 1 minute", 1, scheduledInstances.size()); - TestDiskUsageCalculation.stopLoadInstancesHistory(); + TestDiskUsageCalculation.stopLoadInstancesHistory(); } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java index 97ad0aa1..10acf223 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java @@ -2,55 +2,56 @@ import org.junit.Assert; import org.junit.Test; + /** * * @author Lucie Votypkova */ -public class DiskUsageUtilTest { - +public class DiskUsageUtilTest { + @Test - public void testGetSizeInBytes(){ + public void testGetSizeInBytes() { String sizeInString = "57 B"; Long size = 57l; Assert.assertEquals("Byte representation of size 57 B is wrong.", 57, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "5 KB"; - size = 1024l*5; + size = 1024l * 5; Assert.assertEquals("Byte representation of size 5 KB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "9 MB"; - size = 1024l*1024*9; + size = 1024l * 1024 * 9; Assert.assertEquals("Byte representation of size 9 MB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "1 GB"; - size = 1024l*1024*1024; + size = 1024l * 1024 * 1024; Assert.assertEquals("Byte representation of size 1 GB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "2 TB"; - size = 1024l*1024*1024*1024*2; + size = 1024l * 1024 * 1024 * 1024 * 2; Assert.assertEquals("Byte representation of size 2 TB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "-"; - Assert.assertEquals("Byte representation of size - is wrong.", 0, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assert.assertEquals("Byte representation of size - is wrong.", 0, DiskUsageUtil.getSizeInBytes(sizeInString), 0); } - + @Test - public void testGetSizeInString(){ - String sizeInString = "57 B"; + public void testGetSizeInString() { + String sizeInString = "57 B"; Long size = 57l; Assert.assertEquals("String representation of size 57 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "5 KB"; - size = 1024l*5; + size = 1024l * 5; Assert.assertEquals("String representation of size 5 KB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "9 MB"; - size = 1024l*1024*9; + size = 1024l * 1024 * 9; Assert.assertEquals("String representation of size 9 MB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "1 GB"; - size = 1024l*1024*1024; + size = 1024l * 1024 * 1024; Assert.assertEquals("String representation of size 1 GB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "2 TB"; - size = 1024l*1024*1024*1024*2; + size = 1024l * 1024 * 1024 * 1024 * 2; Assert.assertEquals("String representation of size 2 TB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "-"; - size=0l; - Assert.assertEquals("String representation of size 0 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); - + size = 0l; + Assert.assertEquals("String representation of size 0 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java index 39e352b5..d77e0b1b 100644 --- a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java +++ b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java @@ -17,50 +17,50 @@ * * @author lucinka */ -public class TestDiskUsageCalculation extends BuildDiskUsageCalculationThread{ - +public class TestDiskUsageCalculation extends BuildDiskUsageCalculationThread { + private String cron; - public boolean executing=false; + public boolean executing = false; private boolean sleep = false; - + private static List instancesHistory; - + private static int maxInstances = 10; - + private static TestDiskUsageCalculation currentInstance; - public TestDiskUsageCalculation(String cron, boolean sleep){ + public TestDiskUsageCalculation(String cron, boolean sleep) { this.cron = cron; this.sleep = true; } - public void setCron(String cron){ + public void setCron(String cron) { this.cron = cron; } @Override public CronTab getCronTab() throws ANTLRException { - return new CronTab(cron); + return new CronTab(cron); } - - public static void startLoadInstancesHistory(List history){ + + public static void startLoadInstancesHistory(List history) { TestDiskUsageCalculation.instancesHistory = history; } - - public static void stopLoadInstancesHistory(){ + + public static void stopLoadInstancesHistory() { TestDiskUsageCalculation.instancesHistory = null; } - + @Override public void execute(TaskListener listener) { - executing=true; - if(sleep){ + executing = true; + if(sleep) { try { Thread.sleep(10000); } catch (InterruptedException ex) { - executing=false; + executing = false; } } executing = false; @@ -69,23 +69,22 @@ public void execute(TaskListener listener) { @Override public AperiodicWork getNewInstance() { TestDiskUsageCalculation c = new TestDiskUsageCalculation(cron, sleep); - if(instancesHistory!=null){ - if(maxInstances<=instancesHistory.size()){ + if(instancesHistory != null) { + if(maxInstances <= instancesHistory.size()) { instancesHistory.get(0).cancel(); instancesHistory.remove(0); } instancesHistory.add(c); } - if(currentInstance!=null){ + if(currentInstance != null) { currentInstance.cancel(); - } - else{ + }else { cancel(); } currentInstance = c; return currentInstance; } - + @Override public DiskUsageCalculation getLastTask() { return currentInstance; diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index 5377cbcf..1ea2c6ed 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -20,12 +20,12 @@ * @author Lucie Votypkova */ public class BuildDiskUsageActionTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test - public void testGetAllDiskUsage() throws Exception{ + public void testGetAllDiskUsage() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -51,23 +51,23 @@ public void testGetAllDiskUsage() throws Exception{ int count = 1; Long matrixBuild1TotalSize = sizeOfMatrixBuild1; Long matrixBuild2TotalSize = sizeOfMatrixBuild2; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); - matrixBuild1TotalSize += count*size1; + matrixBuild1TotalSize += count * size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); - matrixBuild2TotalSize += count*size2; + matrixBuild2TotalSize += count * size2; count++; } assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage()); assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).getAllDiskUsage()); assertEquals("BuildDiskUsageAction for build 2 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild2TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).getAllDiskUsage()); - + } - + @Test - public void getBuildUsageStringMatrixProject() throws Exception{ + public void getBuildUsageStringMatrixProject() throws Exception { MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); TextAxis axis2 = new TextAxis("axis2", "Aaxis", "Baxis", "Caxis"); @@ -80,10 +80,10 @@ public void getBuildUsageStringMatrixProject() throws Exception{ matrixProject.setAxes(list); Long kiloBytes = 2048l; int count = 0; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); - for(Action action : configurationBuild.getAllActions()){ - if(action instanceof BuildDiskUsageAction){ + for(Action action: configurationBuild.getAllActions()) { + if(action instanceof BuildDiskUsageAction) { BuildDiskUsageAction a = (BuildDiskUsageAction) action; a.setDiskUsage(kiloBytes); } @@ -91,28 +91,28 @@ public void getBuildUsageStringMatrixProject() throws Exception{ count++; } BuildDiskUsageAction action = null; - for(Action a: matrixBuild.getAllActions()){ - if(a instanceof BuildDiskUsageAction){ + for(Action a: matrixBuild.getAllActions()) { + if(a instanceof BuildDiskUsageAction) { action = (BuildDiskUsageAction) a ; action.setDiskUsage(kiloBytes); break; } } count++; - String size = (kiloBytes*count/1024) + " KB"; + String size = (kiloBytes * count / 1024) + " KB"; assertEquals("String representation of build disk usage which has " + size + " is wrong.", size, action.getBuildUsageString()); - } - + } + @Test - public void getBuildUsageStringFreeStyleProject() throws Exception{ + public void getBuildUsageStringFreeStyleProject() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); Long bytes = 100l; Long kiloBytes = 2048l; - Long megaBytes = kiloBytes*1024; - Long gygaBytes = megaBytes*1024; - Long teraBytes = gygaBytes*1024; + Long megaBytes = kiloBytes * 1024; + Long gygaBytes = megaBytes * 1024; + Long teraBytes = gygaBytes * 1024; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(bytes); assertEquals("String representation of build disk usage is wrong which has 100 B is wrong.", "100 B", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(kiloBytes); @@ -124,5 +124,5 @@ public void getBuildUsageStringFreeStyleProject() throws Exception{ DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(teraBytes); assertEquals("String representation of build disk usage is wrong which has 2T B is wrong.", "2 TB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index 9b43e607..0811339e 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -35,15 +35,15 @@ * @author Lucie Votypkova */ public class BuildDiskUsageCalculationThreadTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - - private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) throws InterruptedException{ + + private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; //wait until thread ends - for(Thread t : Thread.getAllStackTraces().keySet()){ - if(calculation.name.equals(t.getName())){ + for(Thread t: Thread.getAllStackTraces().keySet()) { + if(calculation.name.equals(t.getName())) { while(thread.isAlive()) { Thread.sleep(100); } @@ -51,104 +51,104 @@ private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) th } } } - - private List readFileList(File file) throws FileNotFoundException, IOException{ + + private List readFileList(File file) throws FileNotFoundException, IOException { List files = new ArrayList(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); - while(line!=null){ + while(line != null) { files.add(new File(path + "/" + line)); line = content.readLine(); } return files; } - - private Long getSize(List files){ + + private Long getSize(List files) { Long lenght = 0l; - for(File file: files){ + for(File file: files) { lenght += file.length(); } return lenght; } - + @Test @LocalData - public void testExecute() throws IOException, InterruptedException{ + public void testExecute() throws IOException, InterruptedException { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject1 = new TreeMap(); - Map buildSizesProject2 = new TreeMap(); + Map buildSizesProject1 = new TreeMap(); + Map buildSizesProject2 = new TreeMap(); FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); - for(AbstractBuild build: project.getBuilds()){ - File file = new File(build.getRootDir(),"fileList"); + for(AbstractBuild build: project.getBuilds()) { + File file = new File(build.getRootDir(), "fileList"); buildSizesProject1.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } - for(AbstractBuild build: project2.getBuilds()){ - File file = new File(build.getRootDir(),"fileList"); + for(AbstractBuild build: project2.getBuilds()) { + File file = new File(build.getRootDir(), "fileList"); buildSizesProject2.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } BuildDiskUsageCalculationThread calculation = new BuildDiskUsageCalculationThread(); - if(calculation.isExecuting()){ - waitUntilThreadEnds(calculation); + if(calculation.isExecuting()) { + waitUntilThreadEnds(calculation); } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - for(AbstractBuild build: buildSizesProject1.keySet()){ + for(AbstractBuild build: buildSizesProject1.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); - assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject1.get(build), size, 0); + assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject1.get(build), size, 0); } - for(AbstractBuild build: buildSizesProject2.keySet()){ + for(AbstractBuild build: buildSizesProject2.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), size, 0); } - + } - + @Test @LocalData - public void testExecuteMatrixProject() throws IOException, InterruptedException{ + public void testExecuteMatrixProject() throws IOException, InterruptedException { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject2 = new TreeMap(); - Map matrixConfigurationBuildsSize = new TreeMap(); + Map buildSizesProject2 = new TreeMap(); + Map matrixConfigurationBuildsSize = new TreeMap(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); - FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); + FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); AbstractBuild matrixBuild = project.getBuildByNumber(1); Long matrixProjectBuildSize = getSize(readFileList(new File(matrixBuild.getRootDir(), "fileList"))) + matrixBuild.getRootDir().length(); - for(AbstractBuild build: project2.getBuilds()){ - File file = new File(build.getRootDir(),"fileList"); + for(AbstractBuild build: project2.getBuilds()) { + File file = new File(build.getRootDir(), "fileList"); buildSizesProject2.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } - for(MatrixConfiguration c: project.getActiveConfigurations()){ + for(MatrixConfiguration c: project.getActiveConfigurations()) { AbstractBuild build = c.getBuildByNumber(1); - File file = new File(build.getRootDir(),"fileList"); + File file = new File(build.getRootDir(), "fileList"); matrixConfigurationBuildsSize.put(c.getDisplayName(), getSize(readFileList(file)) + build.getRootDir().length()); } BuildDiskUsageCalculationThread calculation = new BuildDiskUsageCalculationThread(); - if(calculation.isExecuting()){ - waitUntilThreadEnds(calculation); + if(calculation.isExecuting()) { + waitUntilThreadEnds(calculation); } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); Long size = DiskUsageTestUtil.getBuildDiskUsageAction(project.getBuildByNumber(1)).getDiskUsage(); assertEquals("Build " + project.getBuildByNumber(1).getNumber() + " of project " + project.getDisplayName() + " has wrong build size.", matrixProjectBuildSize, size, 0); - for(AbstractBuild build: buildSizesProject2.keySet()){ + for(AbstractBuild build: buildSizesProject2.keySet()) { Long sizeFreeStyle = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), sizeFreeStyle, 0); } - for(MatrixConfiguration conf: project.getActiveConfigurations()){ + for(MatrixConfiguration conf: project.getActiveConfigurations()) { AbstractBuild build = conf.getBuildByNumber(1); - assertEquals("Configuration " + conf.getDisplayName() + " has wrong build size for build 1.", matrixConfigurationBuildsSize.get(conf.getDisplayName()), DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), 0); + assertEquals("Configuration " + conf.getDisplayName() + " has wrong build size for build 1.", matrixConfigurationBuildsSize.get(conf.getDisplayName()), DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), 0); } - + } - + @Test - public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ + public void testDoNotCalculateUnenabledDiskUsage() throws Exception { FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); FreeStyleBuild build = projectWithoutDiskUsage.createExecutable(); build.save(); @@ -158,16 +158,16 @@ public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ assertEquals("Disk usage for build should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage(), 0); DiskUsageProjectActionFactory.DESCRIPTOR.enableBuildsDiskUsageCalculation(); } - + @Test - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception{ - TestFreeStyleProject project = new TestFreeStyleProject(j.jenkins, "project"); + public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { + TestFreeStyleProject project = new TestFreeStyleProject(j.jenkins, "project"); FreeStyleBuild build = new FreeStyleBuild(project); project.addBuild(build); j.jenkins.putItem(project); final BuildDiskUsageCalculationThread testCalculation = new BuildDiskUsageCalculationThread(); Thread t = new Thread(){ - public void run(){ + public void run() { try { testCalculation.execute(TaskListener.NULL); } catch (IOException ex) { @@ -183,37 +183,37 @@ public void run(){ assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(project.getLastBuild()).getAllDiskUsage(), 0); t.interrupt(); } - - public class TestFreeStyleProject extends FreeStyleProject{ - - public TestFreeStyleProject(ItemGroup group, String name){ + + public class TestFreeStyleProject extends FreeStyleProject { + + public TestFreeStyleProject(ItemGroup group, String name) { super(group, name); onCreatedFromScratch(); } - - @Override - public File getBuildDir(){ - //is called during disk calculation, to be sure that calculation is in progress I make this operation longer - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - Logger.getLogger(JobDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); - } - return super.getBuildDir(); - } - - public void addBuild(FreeStyleBuild build){ - builds.put(build); - } - - @Override - public void save(){ - //do not want save + + @Override + public File getBuildDir() { + //is called during disk calculation, to be sure that calculation is in progress I make this operation longer + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + Logger.getLogger(JobDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } + return super.getBuildDir(); + } + + public void addBuild(FreeStyleBuild build) { + builds.put(build); + } + + @Override + public void save() { + //do not want save + } } - + @Test - public void testDoNotCalculateExcludedJobs() throws Exception{ + public void testDoNotCalculateExcludedJobs() throws Exception { FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); List excludes = new ArrayList(); @@ -228,19 +228,19 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ assertTrue("Disk usage for excluded project should not be counted.", DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage() > 0); excludes.clear(); } - + @Test @LocalData - public void testDoNotBreakLazyLoading() throws IOException, InterruptedException{ - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - - //method isBuilding() is used for determining disk usage and its calling load some builds - project.isBuilding(); - int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("Test does not sense if there are all builds loaded, please rewrite it.", loadedBuilds < 8); - BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); - calculation.execute(TaskListener.NULL); - waitUntilThreadEnds(calculation); - assertEquals("Calculation of build disk usage should not cause loading of builds.", loadedBuilds, project._getRuns().getLoadedBuilds().size()); + public void testDoNotBreakLazyLoading() throws IOException, InterruptedException { + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + + //method isBuilding() is used for determining disk usage and its calling load some builds + project.isBuilding(); + int loadedBuilds = project._getRuns().getLoadedBuilds().size(); + assertTrue("Test does not sense if there are all builds loaded, please rewrite it.", loadedBuilds < 8); + BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); + calculation.execute(TaskListener.NULL); + waitUntilThreadEnds(calculation); + assertEquals("Calculation of build disk usage should not cause loading of builds.", loadedBuilds, project._getRuns().getLoadedBuilds().size()); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index 5ff45e39..0d23c725 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -22,12 +22,12 @@ * @author Lucie Votypkova */ public class DiskUsageBuildListenerTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test - public void testOnDeleted() throws Exception{ + public void testOnDeleted() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); @@ -38,11 +38,11 @@ public void testOnDeleted() throws Exception{ assertNotNull("Disk usage property whoud contains cashed information about build 1.", property.getDiskUsageOfBuild(1)); assertNotNull("Disk usage property whoud contains cashed information about build 3.", property.getDiskUsageOfBuild(3)); } - + @Test - public void testOnCompleted() throws Exception{ + public void testOnCompleted() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); - if (Functions.isWindows()){ + if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo ahoj > log.log")); } else { project.getBuildersList().add(new Shell("echo ahoj > log.log")); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 3460e3df..351d14f7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -22,12 +22,12 @@ * @author Lucie Votypkova */ public class DiskUsagePluginTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test - public void testRefreshGlobalInformation() throws IOException{ + public void testRefreshGlobalInformation() throws IOException { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); FreeStyleBuild build1 = project.createExecutable(); FreeStyleBuild build2 = project.createExecutable(); @@ -42,7 +42,7 @@ public void testRefreshGlobalInformation() throws IOException{ Long workspaceUsage = 20345l; Long jobUsage = 5980l; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - if(property==null){ + if(property == null) { property = new DiskUsageProperty(); project.addProperty(property); } @@ -52,12 +52,12 @@ public void testRefreshGlobalInformation() throws IOException{ assertEquals("Global build diskUsage should be refreshed.", sizeofBuild1 + sizeofBuild2 + sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0); assertEquals("Global job diskUsage should be refreshed.", jobUsage, plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), 0); assertEquals("Global workspace diskUsage should be refreshed.", workspaceUsage, plugin.getCashedGlobalWorkspacesDiskUsage(), 0); - + } - + @Test @LocalData - public void testNotBreakLazyLoading() throws IOException{ + public void testNotBreakLazyLoading() throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); @@ -65,10 +65,10 @@ public void testNotBreakLazyLoading() throws IOException{ assertEquals("Size of builds should be loaded.", 47000, j.jenkins.getPlugin(DiskUsagePlugin.class).getCashedGlobalBuildsDiskUsage(), 0); assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); } - + @Test @LocalData - public void testDoNotLoadAllBuildsDuringStart(){ + public void testDoNotLoadAllBuildsDuringStart() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); @@ -76,21 +76,21 @@ public void testDoNotLoadAllBuildsDuringStart(){ loadedBuilds = project2._getRuns().getLoadedBuilds().size(); assertEquals("Builds of project without disk-usage.xml should not be loaded.", 0, loadedBuilds); } - + @Test @LocalData - public void testDoLoadBuildInformationWhenBuildIsLoaded(){ - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuild("1"); - int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertNotNull("Build should be add after its loading (if it is not present before).", property.getDiskUsageOfBuild(2)); - assertEquals("Only required build should be loaded into Jenkins.", 1, loadedBuilds); + public void testDoLoadBuildInformationWhenBuildIsLoaded() { + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractBuild build = project.getBuild("1"); + int loadedBuilds = project._getRuns().getLoadedBuilds().size(); + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + assertNotNull("Build should be add after its loading (if it is not present before).", property.getDiskUsageOfBuild(2)); + assertEquals("Only required build should be loaded into Jenkins.", 1, loadedBuilds); } - + @Test - @LocalData - public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception{ + @LocalData + public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuild("2"); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -101,6 +101,6 @@ public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception{ property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Should be loaded build 2", property.getDiskUsageBuildInformation(2)); assertEquals("Only one build should be loaded into disk usage build information.", 1, property.getDiskUsageOfBuilds().size()); - + } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index a58a7b60..221ea557 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -47,13 +47,13 @@ * @author Lucie Votypkova */ public class DiskUsagePropertyTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - - + + @Test - public void testGetAllDiskUsageWithoutBuilds() throws Exception{ + public void testGetAllDiskUsageWithoutBuilds() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -61,7 +61,7 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception{ AxisList list = new AxisList(); list.add(axis1); list.add(axis2); - matrixProject.setAxes(list); + matrixProject.setAxes(list); Long sizeOfProject = 7546l; Long sizeOfMatrixProject = 6800l; DiskUsageProperty projectProperty = project.getProperty(DiskUsageProperty.class); @@ -72,20 +72,20 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception{ long size1 = 5390; int count = 1; Long matrixProjectTotalSize = sizeOfMatrixProject; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { DiskUsageProperty configurationProperty = new DiskUsageProperty(); c.addProperty(configurationProperty); - configurationProperty.setDiskUsageWithoutBuilds(count * size1); - matrixProjectTotalSize += count*size1; + configurationProperty.setDiskUsageWithoutBuilds(count * size1); + matrixProjectTotalSize += count * size1; //matrixProjectTotalSize += c.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); count++; } assertEquals("DiskUsageProperty for FreeStyleProject " + project.getDisplayName() + " returns wrong value its size without builds and including sub-projects.", sizeOfProject, project.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); assertEquals("DiskUsageProperty for MatrixProject " + project.getDisplayName() + " returns wrong value for its size without builds and including sub-projects.", matrixProjectTotalSize, matrixProject.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); } - + @Test - public void testCheckWorkspaces() throws Exception{ + public void testCheckWorkspaces() throws Exception { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -98,7 +98,7 @@ public void testCheckWorkspaces() throws Exception{ j.buildAndAssertSuccess(project); project.getBuildByNumber(1).delete(); DiskUsageProperty prop = project.getProperty(DiskUsageProperty.class); - if(prop == null){ + if(prop == null) { prop = new DiskUsageProperty(); project.addProperty(prop); } @@ -109,12 +109,12 @@ public void testCheckWorkspaces() throws Exception{ j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnSlave(true); prop.checkWorkspaces(); assertTrue("DiskUsage property should contains slave " + slave2.getDisplayName() + " in slaveWorkspaceUsage.", nodes.contains(slave2.getNodeName())); - assertTrue("DiskUsage property should contains slave " + slave1.getDisplayName() + " in slaveWorkspaceUsage when detection of user workspace withour reference from project is set.", nodes.contains(slave1.getNodeName())); + assertTrue("DiskUsage property should contains slave " + slave1.getDisplayName() + " in slaveWorkspaceUsage when detection of user workspace withour reference from project is set.", nodes.contains(slave1.getNodeName())); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnSlave(false); } - + @Test - public void getWorkspaceSizeTest() throws Exception{ + public void getWorkspaceSizeTest() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -127,25 +127,25 @@ public void getWorkspaceSizeTest() throws Exception{ project.setCustomWorkspace(j.jenkins.getRootDir().getAbsolutePath() + "/project-custom-workspace"); j.buildAndAssertSuccess(project); DiskUsageProperty prop = project.getProperty(DiskUsageProperty.class); - if(prop == null){ + if(prop == null) { prop = new DiskUsageProperty(); project.addProperty(prop); } prop.checkWorkspaces(); Long workspaceSize = 7509l; - Map> diskUsage = prop.getSlaveWorkspaceUsage(); - for(String name : diskUsage.keySet()){ - Map slaveInfo = diskUsage.get(name); - for(String path: slaveInfo.keySet()){ + Map> diskUsage = prop.getSlaveWorkspaceUsage(); + for(String name: diskUsage.keySet()) { + Map slaveInfo = diskUsage.get(name); + for(String path: slaveInfo.keySet()) { slaveInfo.put(path, workspaceSize); } } assertEquals("DiskUsage workspaces which is configured as slave workspace is wrong.", workspaceSize * 2, prop.getWorkspaceSize(true), 0); assertEquals("DiskUsage workspaces which is not configured as slave workspace is wrong.", workspaceSize, prop.getWorkspaceSize(false), 0); } - + @Test - public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception{ + public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); @@ -162,11 +162,11 @@ public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception{ property.checkWorkspaces(); assertFalse("Disk usage property should not contains slave which does not exist.", property.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); assertTrue("Disk usage property should contains slave1.", property.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); - } - + assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + } + @Test - public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception{ + public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); @@ -182,31 +182,31 @@ public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception{ property.checkWorkspaces(); assertFalse("Disk usage property should not contains slave which does not have any workspace for its project.", property.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); assertTrue("Disk usage property should contains slave2.", property.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); path.delete(); property.checkWorkspaces(); - assertFalse("Disk usage property should contains jenkins master, because workspace for its project was deleted.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); - + assertFalse("Disk usage property should contains jenkins master, because workspace for its project was deleted.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + } - + @Test - public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Exception{ + public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - if (Functions.isWindows()){ + if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); } else { project.getBuildersList().add(new Shell("echo hello > log")); } Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(), "SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave slave1 = j.createOnlineSlave(); - Slave slave2= j.createOnlineSlave(); - File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName()+ "/log"); + Slave slave2 = j.createOnlineSlave(); + File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName() + "/log"); //DiskUsageTestUtil.createFileWithContent(workspaceSlave1); File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); //DiskUsageTestUtil.createFileWithContent(workspaceSlave2); - File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(),"custom2/log"); + File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); //DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave1); - File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(),"custom1/log"); + File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); //DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave2); project.setAssignedLabel(slave3.getSelfLabel()); j.buildAndAssertSuccess(project); @@ -223,19 +223,19 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep slave1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); } - + @Test - public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception{ + public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - if (Functions.isWindows()){ + if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); } else { project.getBuildersList().add(new Shell("echo hello > log")); } Slave slave1 = j.createOnlineSlave(); File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); - File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(),"custom2/log"); - File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(),"custom1/log"); + File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); + File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); j.jenkins.setNumExecutors(1); project.setAssignedLabel(j.jenkins.getSelfLabel()); j.buildAndAssertSuccess(project); @@ -252,10 +252,10 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception j.jenkins.setNumExecutors(0); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); } - + @Test @LocalData - public void testBackwadrCompatibility1() throws IOException{ + public void testBackwadrCompatibility1() throws IOException { j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableBuildsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableJobsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableWorkspacesDiskUsageCalculation(); @@ -265,12 +265,12 @@ public void testBackwadrCompatibility1() throws IOException{ assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); assertEquals("Size of build 2 should be loaded from previous configuration.", 23932L, property.getDiskUsageOfBuild(2), 0); } - - + + @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml") @LocalData - public void testBackwadrCompatibility2() throws IOException{ + public void testBackwadrCompatibility2() throws IOException { j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableBuildsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableJobsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableWorkspacesDiskUsageCalculation(); @@ -281,53 +281,53 @@ public void testBackwadrCompatibility2() throws IOException{ assertEquals("Size of workspaces should be loaded from previous configuration.", 4096L, property.getAllWorkspaceSize(), 0); assertTrue("Path of workspace shoudl be loaded form previous configuration.", property.getSlaveWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); } - + @Test @LocalData - public void testGetDiskUsageOfBuilds(){ + public void testGetDiskUsageOfBuilds() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - for(DiskUsageBuildInformation information : property.getDiskUsageOfBuilds()){ + for(DiskUsageBuildInformation information: property.getDiskUsageOfBuilds()) { assertEquals("Disk usage of build has loaded wrong size.", information.getNumber() * 1000, information.getSize(), 0); } assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); - } - - + } + + @Test @LocalData - public void testGetDiskUsageOfBuild(){ + public void testGetDiskUsageOfBuild() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild("1"), 0); assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild("7"), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); - } - + } + @Test @LocalData - public void testGetDiskUsageBuildInformation(){ + public void testGetDiskUsageBuildInformation() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageBuildInformation("1").getSize(), 0); assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageBuildInformation("7").getSize(), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); - } - + } + @Test @LocalData - public void testGetDiskUsageOfBuildByNumber(){ + public void testGetDiskUsageOfBuildByNumber() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild(1), 0); assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild(7), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); - - } + + } @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/disk-usage.xml") @@ -341,29 +341,29 @@ public void testCheckWorkspacesBuildsWithoutLoadingBuilds() throws IOException, assertEquals("Workspace should have size 4096", 4096, property.getAllWorkspaceSize(), 0); assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); } - + @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml, jobs/project1/builds/1/build.xml, jobs/project1/builds/3/build.xml") @LocalData public void testCheckWorkspacesWithLoadingBuilds() throws IOException { - File file = new File(j.jenkins.getRootDir(),"jobs/project2/builds/1/build.xml"); - XmlFile f = new XmlFile(new XStream2(), file); - String newBuildXml = f.asString().replace("${JENKINS_HOME}", j.jenkins.getRootDir().getAbsolutePath()); - PrintStream st = new PrintStream(file); - st.print(newBuildXml); - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - DiskUsageProperty property2 = (DiskUsageProperty) project2.getProperty(DiskUsageProperty.class); - property2.getDiskUsage().loadAllBuilds(); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace", property.getSlaveWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace")); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/workspace", property2.getSlaveWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); - - assertEquals("Builds should be loaded.", 2, project2._getRuns().getLoadedBuilds().size(), 0); + File file = new File(j.jenkins.getRootDir(), "jobs/project2/builds/1/build.xml"); + XmlFile f = new XmlFile(new XStream2(), file); + String newBuildXml = f.asString().replace("${JENKINS_HOME}", j.jenkins.getRootDir().getAbsolutePath()); + PrintStream st = new PrintStream(file); + st.print(newBuildXml); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + DiskUsageProperty property2 = (DiskUsageProperty) project2.getProperty(DiskUsageProperty.class); + property2.getDiskUsage().loadAllBuilds(); + assertTrue("Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace", property.getSlaveWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace")); + assertTrue("Project should contains workspace with path {JENKINS_HOME}/workspace", property2.getSlaveWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + + assertEquals("Builds should be loaded.", 2, project2._getRuns().getLoadedBuilds().size(), 0); } - + @Test - public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ + public void testGetAllDiskUsageOfBuild() throws IOException, Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -389,13 +389,13 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ int count = 1; Long matrixBuild1TotalSize = sizeOfMatrixBuild1; Long matrixBuild2TotalSize = sizeOfMatrixBuild2; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); - matrixBuild1TotalSize += count*size1; + matrixBuild1TotalSize += count * size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); - matrixBuild2TotalSize += count*size2; + matrixBuild2TotalSize += count * size2; count++; } hudson.plugins.disk_usage.DiskUsageProperty freeStyleProjectProperty = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -403,23 +403,23 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception{ assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, freeStyleProjectProperty.getAllDiskUsageOfBuild(1)); assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(1)); assertEquals("BuildDiskUsageAction for build 2 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild2TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(2)); - + } - + @Test @LocalData - public void testDoNotBreakLazyLoading(){ + public void testDoNotBreakLazyLoading() { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertEquals("Size of builds should be loaded.", 1000, property.getAllDiskUsageOfBuild(8), 0); assertEquals("Size of builds should be loaded.", 7000, property.getAllDiskUsageOfBuild(4), 0); - assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); + assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); } - + @Test - public void testRemoveBuild() throws Exception{ + public void testRemoveBuild() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); @@ -429,9 +429,9 @@ public void testRemoveBuild() throws Exception{ build.delete(); assertEquals("Deleted build should be removed from disk-usage informations too.", 1, property.getDiskUsage().getBuildDiskUsage(false).size()); } - + @Test - public void testRemoveDeletedBuildNotLoadedByJenkins() throws Exception{ + public void testRemoveDeletedBuildNotLoadedByJenkins() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); @@ -446,147 +446,148 @@ public void testRemoveDeletedBuildNotLoadedByJenkins() throws Exception{ project = (FreeStyleProject) j.jenkins.getItem(project.getDisplayName()); property = project.getProperty(DiskUsageProperty.class); assertEquals("Deleted build without Jenkins should not be loaded.", 1, property.getDiskUsage().getBuildDiskUsage(false).size()); - + } - - private TestThread runRemoveThread(ProjectDiskUsage usage){ + + private TestThread runRemoveThread(ProjectDiskUsage usage) { final ProjectDiskUsage diskUsage = usage; TestThread removeThread = new TestThread("removeFromSet"){ - public void run(){ - try{ - int count = 0; - while(count < 1000){ + public void run() { + try { + int count = 0; + while(count < 1000) { count++; diskUsage.removeBuild(diskUsage.getDiskUsageBuildInformation(count)); } } catch (ConcurrentModificationException ex) { exception = ex; - }catch (Exception ex){ + } catch (Exception ex) { exception = ex; } - } + } }; removeThread.start(); return removeThread; } - - private TestThread runPutThread(ProjectDiskUsage usage){ + + private TestThread runPutThread(ProjectDiskUsage usage) { final ProjectDiskUsage diskUsage = usage; - TestThread putThread = new TestThread("putIntoSet"){ - public void run(){ + TestThread putThread = new TestThread("putIntoSet"){ + public void run() { try { int count = 0; - while(count < 1000){ + while(count < 1000) { count++; GregorianCalendar calendar = new GregorianCalendar(); calendar.set(2014, 1, 1); calendar.add(GregorianCalendar.MINUTE, count); diskUsage.addBuildInformation(new DiskUsageBuildInformation( - Integer.toString(count), - calendar.getTimeInMillis(), - count, - 0l), null); + Integer.toString(count), + calendar.getTimeInMillis(), + count, + 0l), null); } } catch (ConcurrentModificationException ex) { exception = ex; - }catch (Exception ex){ + } catch (Exception ex) { exception = ex; - } - } + } + } }; putThread.start(); return putThread; } - - private TestThread runSaveThread(ProjectDiskUsage usage){ + + private TestThread runSaveThread(ProjectDiskUsage usage) { final ProjectDiskUsage diskUsage = usage; TestThread saveThread = new TestThread("saveSet"){ - public void run(){ - try{ - int count = 0; - while(count<100){ - count++; - diskUsage.save(); - } - } catch (ConcurrentModificationException ex) { + public void run() { + try { + int count = 0; + while(count < 100) { + count++; + diskUsage.save(); + } + } catch (ConcurrentModificationException ex) { exception = ex; - }catch (Exception ex){ + } catch (Exception ex) { exception = ex; - } - } + } + } }; saveThread.start(); return saveThread; } - - private void checkForConcurrencyException(Exception exception){ + + private void checkForConcurrencyException(Exception exception) { exception.printStackTrace(); - if(exception instanceof ConcurrentModificationException){ + if(exception instanceof ConcurrentModificationException) { fail("DiskUsageProperty is not thread save. Attribute #diskUsageProperty caused ConcurrentModitifiactionException"); return; } fail("Checking of thread safety caused Exception which is not connected with thread safety problem."); } - + //JENKINS-29143 @Test - public void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation() throws Exception{ + public void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation() throws Exception { final FreeStyleProject project = j.createFreeStyleProject(); final ProjectDiskUsage diskUsage = new ProjectDiskUsage(); diskUsage.setProject(project); TestThread putThread = runPutThread(diskUsage); TestThread removeThread = runRemoveThread(diskUsage); TestThread saveThread = runSaveThread(diskUsage); - while(putThread.isAlive() || removeThread.isAlive()|| saveThread.isAlive()){ + while(putThread.isAlive() || removeThread.isAlive() || saveThread.isAlive()) { Thread.currentThread().sleep(1000); } - + Exception ex = putThread.getException(); - if(putThread.getException()!=null){ + if(putThread.getException() != null) { checkForConcurrencyException(ex); } ex = removeThread.getException(); - if(removeThread.getException()!=null){ + if(removeThread.getException() != null) { checkForConcurrencyException(ex); } ex = saveThread.getException(); - if(saveThread.getException()!=null){ + if(saveThread.getException() != null) { checkForConcurrencyException(ex); } } - + public class TestThread extends Thread { - - TestThread(String name){ + + TestThread(String name) { super(name); } - + public Exception exception; - - public Exception getException(){ + + public Exception getException() { return exception; } - + } - - + + @Target(METHOD) @Retention(RUNTIME) @JenkinsRecipe(ReplaceHudsonHomeWithCurrentPath.CurrentWorkspacePath.class) public @interface ReplaceHudsonHomeWithCurrentPath { - + String value() default ""; - - class CurrentWorkspacePath extends JenkinsRecipe.Runner{ + + class CurrentWorkspacePath extends JenkinsRecipe.Runner { private String paths; - public void decorateHome(JenkinsRule rule, File home){ + + public void decorateHome(JenkinsRule rule, File home) { if(paths.isEmpty()) { return; } - for(String path : paths.split(",")){ + for(String path: paths.split(",")) { path = path.trim(); try { - File file = new File(home,path); + File file = new File(home, path); XmlFile xmlFile = new XmlFile(file); String content = xmlFile.asString(); content = content.replace("${JENKINS_HOME}", home.getAbsolutePath()); @@ -598,22 +599,21 @@ public void decorateHome(JenkinsRule rule, File home){ } } } - + @Override public void setup(JenkinsRule jenkinsRule, ReplaceHudsonHomeWithCurrentPath recipe) throws Exception { paths = recipe.value(); } } } - - class WorkspacePathAnnotation implements Annotation{ + + class WorkspacePathAnnotation implements Annotation { public Class annotationType() { return WorkspacePathAnnotation.class; } - + } - - - + + } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index a68b4272..0999eac0 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -31,56 +31,56 @@ * @author Lucie Votypkova */ public class DiskUsageTestUtil { - protected static List readFileList(File file) throws FileNotFoundException, IOException{ + protected static List readFileList(File file) throws FileNotFoundException, IOException { List files = new ArrayList(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); - while(line!=null){ + while(line != null) { files.add(new File(path + "/" + line)); line = content.readLine(); } return files; } - - protected static Long getSize(List files){ + + protected static Long getSize(List files) { Long lenght = 0l; - for(File file: files){ + for(File file: files) { lenght += file.length(); } return lenght; } - - protected static Slave createSlave(String name, String remoteFS, Jenkins jenkins, ComputerLauncher launcher) throws Exception{ + + protected static Slave createSlave(String name, String remoteFS, Jenkins jenkins, ComputerLauncher launcher) throws Exception { DumbSlave slave = new DumbSlave(name, "dummy", - remoteFS, "2", Mode.NORMAL, "", launcher, - RetentionStrategy.NOOP, Collections.>emptyList()); - jenkins.addNode(slave); - while(slave.toComputer()==null || !slave.toComputer().isOnline()){ + remoteFS, "2", Mode.NORMAL, "", launcher, + RetentionStrategy.NOOP, Collections.>emptyList()); + jenkins.addNode(slave); + while(slave.toComputer() == null || !slave.toComputer().isOnline()) { Thread.sleep(100); } return slave; } - - protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build){ - for(Action a : build.getAllActions()){ + + protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build) { + for(Action a: build.getAllActions()) { if(a instanceof BuildDiskUsageAction) { return (BuildDiskUsageAction) a; } } return null; } - - protected static void cancelCalculation(DiskUsageCalculation calculation){ - for(Thread t : Thread.getAllStackTraces().keySet()){ - if(t.getName().equals(calculation.getThreadName())){ - t.interrupt(); - return; - } - } + + protected static void cancelCalculation(DiskUsageCalculation calculation) { + for(Thread t: Thread.getAllStackTraces().keySet()) { + if(t.getName().equals(calculation.getThreadName())) { + t.interrupt(); + return; + } + } } - - protected static void createFileWithContent(File file) throws FileNotFoundException{ + + protected static void createFileWithContent(File file) throws FileNotFoundException { file.getParentFile().mkdirs(); PrintStream stream = new PrintStream(file); stream.println("hello"); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 16908322..8ca97906 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -27,13 +27,13 @@ * @author Lucie Votypkova */ public class DiskUsageUtilTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test @LocalData - public void testCalculateDiskUsageForBuild() throws Exception{ + public void testCalculateDiskUsageForBuild() throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuildByNumber(2); File file = new File(build.getRootDir(), "fileList"); @@ -41,31 +41,31 @@ public void testCalculateDiskUsageForBuild() throws Exception{ DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), project); Assert.assertEquals("Calculation of build disk usage does not return right size of build directory.", size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage()); } - + @Test @LocalData - public void testCalculateDiskUsageForMatrixBuild() throws Exception{ + public void testCalculateDiskUsageForMatrixBuild() throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuildByNumber(1); File file = new File(build.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + build.getRootDir().length(); Long sizeAll = size; - for(MatrixConfiguration config: project.getActiveConfigurations()){ + for(MatrixConfiguration config: project.getActiveConfigurations()) { AbstractBuild b = config.getBuildByNumber(1); File f = new File(b.getRootDir(), "fileList"); sizeAll += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(f)) + b.getRootDir().length(); } DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), project); Assert.assertEquals("Matrix project project1 has disk usage size.", size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage()); - for(MatrixConfiguration config: project.getActiveConfigurations()){ + for(MatrixConfiguration config: project.getActiveConfigurations()) { DiskUsageUtil.calculateDiskUsageForBuild(config.getBuildByNumber(1).getId(), config); } Assert.assertEquals("Matrix project project1 has wrong size for its build.", sizeAll, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage()); } - + @Test @LocalData - public void testCalculateDiskUsageForJob() throws Exception{ + public void testCalculateDiskUsageForJob() throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); //all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -74,12 +74,12 @@ public void testCalculateDiskUsageForJob() throws Exception{ size += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); DiskUsageUtil.calculateDiskUsageForProject(project); Assert.assertEquals("Calculation of job disk usage does not return right size of job without builds.", size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds()); - + } - + @Test @LocalData - public void testCalculateDiskUsageForMatrixJob() throws Exception{ + public void testCalculateDiskUsageForMatrixJob() throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); //all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -87,7 +87,7 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception{ Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + project.getRootDir().length(); size += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); Long sizeAll = size; - for(MatrixConfiguration config: project.getItems()){ + for(MatrixConfiguration config: project.getItems()) { config.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File f = new File(config.getRootDir(), "fileList"); sizeAll += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(f)) + config.getRootDir().length(); @@ -95,17 +95,17 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception{ } DiskUsageUtil.calculateDiskUsageForProject(project); Assert.assertEquals("Calculation of job disk usage does not return right size of job without builds.", size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds()); - for(AbstractProject p: project.getItems()){ + for(AbstractProject p: project.getItems()) { DiskUsageUtil.calculateDiskUsageForProject(p); } Assert.assertEquals("Calculation of job disk usage does not return right size of job and its sub-jobs without builds.", sizeAll, project.getAction(ProjectDiskUsageAction.class).getAllDiskUsageWithoutBuilds()); - + } - + @Test @LocalData - public void testCalculateDiskUsageWorkspaceForProject() throws Exception{ - //turn off run listener + public void testCalculateDiskUsageWorkspaceForProject() throws Exception { + //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -134,14 +134,14 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception{ @Test @LocalData - public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory() throws Exception{ - //turn off run listener + public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory() throws Exception { + //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); j.jenkins.setNumExecutors(0); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); - TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); + TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); @@ -150,51 +150,51 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); ArrayList slaves = new ArrayList(); slaves.add("slave2"); - LabelAxis axis2 = new LabelAxis("label",slaves); + LabelAxis axis2 = new LabelAxis("label", slaves); axes.add(axis2); project1.setAxes(axes); File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis1", "fileList"); - File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); - File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); + File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); - for(MatrixConfiguration c: project1.getItems()){ + for(MatrixConfiguration c: project1.getItems()) { DiskUsageUtil.calculateWorkspaceDiskUsage(c); } DiskUsageUtil.calculateWorkspaceDiskUsage(project1); Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - + Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - - + + //next build - configuration are builded on next slave //test if not active configuration are find and right counted // test if works with more complex configurations j.buildAndAssertSuccess(project1); - for(MatrixConfiguration c: project1.getItems()){ + for(MatrixConfiguration c: project1.getItems()) { DiskUsageUtil.calculateWorkspaceDiskUsage(c); } DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - + Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2", "fileList"); - fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2", "fileList"); - fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2", "fileList"); + fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2", "fileList"); + fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2", "fileList"); + fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2", "fileList"); sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - - + + //matrix project is builded on the next slave //test if new folder on slave2 is counted too project1.setAssignedNode(slave2); @@ -204,19 +204,19 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa DiskUsageUtil.calculateWorkspaceDiskUsage(project1); Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } - + @Test @LocalData - public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() throws Exception{ - //turn off run listener + public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() throws Exception { + //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); - plugin.getConfiguration().setCheckWorkspaceOnSlave(true); + plugin.getConfiguration().setCheckWorkspaceOnSlave(true); j.jenkins.setNumExecutors(0); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); - TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); + TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); @@ -225,22 +225,22 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - File fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1/label/slave2", "fileList"); - File fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2/label/slave2", "fileList"); - File fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3/label/slave2", "fileList"); + File fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2", "fileList"); + File fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2", "fileList"); + File fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2", "fileList"); Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave2.getWorkspaceFor(project1).length() + sizeAxis1 + sizeAxis2 + sizeAxis3; DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); plugin.getConfiguration().setCheckWorkspaceOnSlave(false); } - - + + @Test - public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception{ + public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -248,9 +248,9 @@ public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesN FreeStyleProject project1 = j.createFreeStyleProject("project1"); project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); - + DiskUsageProperty prop = project1.getProperty(DiskUsageProperty.class); - if(prop == null){ + if(prop == null) { prop = new DiskUsageProperty(); project1.addProperty(prop); } @@ -259,9 +259,9 @@ public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesN assertFalse("Slave slave2 should be removed from disk usage, because a workspace for project1 does not exist on this slave.", prop.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); assertTrue("Disk usage should contains slave1, there is a workspace for project1.", prop.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); } - + @Test - public void testParseExcludedJobsFromString() throws Exception{ + public void testParseExcludedJobsFromString() throws Exception { FreeStyleProject projectWithSpace = j.createFreeStyleProject("Project with space"); FreeStyleProject project = j.createFreeStyleProject("Project"); FreeStyleProject project2 = j.createFreeStyleProject("Project2"); @@ -281,5 +281,5 @@ public void testParseExcludedJobsFromString() throws Exception{ excluded = "Project with space, "; assertTrue("Excluded jobs should be parsed correctly even if there additional separator", excludedJobs.contains(projectWithSpace.getName()) && excludedJobs.size() == 1); } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index f6590a73..7ef33988 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -36,35 +36,35 @@ public class JobDiskUsageCalculationThreadTest { @Rule public JenkinsRule j = new JenkinsRule(); - private void waitUntilThreadEnds(JobWithoutBuildsDiskUsageCalculation calculation) throws InterruptedException{ - while(calculation.isExecuting()){ + private void waitUntilThreadEnds(JobWithoutBuildsDiskUsageCalculation calculation) throws InterruptedException { + while(calculation.isExecuting()) { Thread.sleep(100); } } - - private List readFileList(File file) throws FileNotFoundException, IOException{ + + private List readFileList(File file) throws FileNotFoundException, IOException { List files = new ArrayList(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); - while(line!=null){ + while(line != null) { files.add(new File(path + "/" + line)); line = content.readLine(); } return files; } - - private Long getSize(List files){ + + private Long getSize(List files) { Long length = 0l; - for(File file: files){ + for(File file: files) { length += file.length(); } - return length; + return length; } - + @Test @LocalData - public void testExecute() throws IOException, InterruptedException{ + public void testExecute() throws IOException, InterruptedException { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -74,14 +74,14 @@ public void testExecute() throws IOException, InterruptedException{ //we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); - File file = new File(project.getRootDir(),"fileList"); + File file = new File(project.getRootDir(), "fileList"); Long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); - file = new File(project2.getRootDir(),"fileList"); + file = new File(project2.getRootDir(), "fileList"); Long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); projectSize += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); - project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); + project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); - if(calculation.isExecuting()){ + if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); } calculation.execute(TaskListener.NULL); @@ -89,29 +89,29 @@ public void testExecute() throws IOException, InterruptedException{ assertEquals("Project project has wrong job size.", projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); assertEquals("Project project2 has wrong job size.", project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); } - + @Test @LocalData - public void testMatrixProject() throws IOException, InterruptedException{ + public void testMatrixProject() throws IOException, InterruptedException { //turn off run listener DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map matrixConfigurationsSize = new TreeMap(); + Map matrixConfigurationsSize = new TreeMap(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); //we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); - project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); - File file = new File(project.getRootDir(),"fileList"); + project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); + File file = new File(project.getRootDir(), "fileList"); Long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); - file = new File(project2.getRootDir(),"fileList"); + file = new File(project2.getRootDir(), "fileList"); Long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); projectSize += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); - project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); - for(MatrixConfiguration config: project.getItems()){ + project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); + for(MatrixConfiguration config: project.getItems()) { config.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); - File f = new File(config.getRootDir(),"fileList"); + File f = new File(config.getRootDir(), "fileList"); Long size = getSize(readFileList(f)) + config.getRootDir().length(); long diskUsageXML = config.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); matrixConfigurationsSize.put(config.getDisplayName(), size + diskUsageXML); @@ -124,19 +124,19 @@ public void testMatrixProject() throws IOException, InterruptedException{ waitUntilThreadEnds(calculation); assertEquals("Project project has wrong job size.", projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); assertEquals("Project project2 has wrong job size.", project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); - for(MatrixConfiguration config: project.getItems()){ - assertEquals("Configuration " + config.getDisplayName() + " has wrong job size.", matrixConfigurationsSize.get(config.getDisplayName()), config.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); + for(MatrixConfiguration config: project.getItems()) { + assertEquals("Configuration " + config.getDisplayName() + " has wrong job size.", matrixConfigurationsSize.get(config.getDisplayName()), config.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); } } - - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception{ + + public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); DiskUsageTestUtil.cancelCalculation(calculation); FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, j.contextPath); final JobWithoutBuildsDiskUsageCalculation testCalculation = new JobWithoutBuildsDiskUsageCalculation(); Thread t = new Thread(testCalculation.getThreadName()){ @Override - public void run(){ + public void run() { try { Thread.sleep(10000); } catch (Exception ex) { @@ -150,8 +150,8 @@ public void run(){ assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0l, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); t.interrupt(); } - - public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ + + public void testDoNotCalculateUnenabledDiskUsage() throws Exception { FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); DiskUsageProjectActionFactory.DESCRIPTOR.disableJobsDiskUsageCalculation(); JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); @@ -159,9 +159,9 @@ public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ assertEquals("Disk usage for build should not be counted.", 0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0); DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); } - + @Test - public void testDoNotCalculateExcludedJobs() throws Exception{ + public void testDoNotCalculateExcludedJobs() throws Exception { JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); @@ -176,5 +176,5 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ assertTrue("Disk usage for included project should be not be counted.", includedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds() > 0); excludes.clear(); } - + } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 0f962386..7b1547ad 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -32,12 +32,12 @@ * @author Lucie Votypkova */ public class ProjectDiskUsageActionTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test - public void testGetBuildsDiskUsage() throws Exception{ + public void testGetBuildsDiskUsage() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -63,23 +63,23 @@ public void testGetBuildsDiskUsage() throws Exception{ int count = 1; Long matrixBuild1TotalSize = sizeOfMatrixBuild1; Long matrixBuild2TotalSize = sizeOfMatrixBuild2; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); - matrixBuild1TotalSize += count*size1; + matrixBuild1TotalSize += count * size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); - matrixBuild2TotalSize += count*size2; + matrixBuild2TotalSize += count * size2; count++; } Long matrixProjectBuildsTotalSize = matrixBuild1TotalSize + matrixBuild2TotalSize; assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - + assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); + } - + @Test - public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception{ + public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -105,24 +105,24 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception{ int count = 1; Long matrixBuild1TotalSize = sizeOfMatrixBuild1; Long matrixBuild2TotalSize = sizeOfMatrixBuild2; - for(MatrixConfiguration c: matrixProject.getItems()){ + for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); - matrixBuild1TotalSize += count*size1; + matrixBuild1TotalSize += count * size1; AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); - matrixBuild2TotalSize += count*size2; + matrixBuild2TotalSize += count * size2; count++; } matrixBuild2.delete(); Long matrixProjectBuildsTotalSize = matrixBuild1TotalSize + matrixBuild2TotalSize - sizeOfMatrixBuild2; assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - + assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); + } - + @Test - public void getAllBuildDiskUsageFiltered() throws Exception{ + public void getAllBuildDiskUsageFiltered() throws Exception { ProjectTest project = new ProjectTest(j.jenkins, "project"); Calendar calendar1 = new GregorianCalendar(); Calendar calendar2 = new GregorianCalendar(); @@ -151,7 +151,7 @@ public void getAllBuildDiskUsageFiltered() throws Exception{ DiskUsageTestUtil.getBuildDiskUsageAction(build2).setDiskUsage(sizeofBuild2); DiskUsageTestUtil.getBuildDiskUsageAction(build3).setDiskUsage(sizeofBuild3); project.update(); - Map size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(null, youngerThan10days); + Map size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(null, youngerThan10days); assertEquals("Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago).", sizeofBuild1, size.get("all"), 0); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan7days, youngerThan10days); assertEquals("Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago and older than 8 days ago).", 0, size.get("all"), 0); @@ -164,71 +164,71 @@ public void getAllBuildDiskUsageFiltered() throws Exception{ size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan3weeks, null); assertEquals("Disk usage of builds should count only build 3 (only build 3 is older tah 3 weeks).", sizeofBuild3, size.get("all"), 0); - + } - + @Test @LocalData - public void testNotToBreakLazyLoading() throws IOException{ + public void testNotToBreakLazyLoading() throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); project.getAction(ProjectDiskUsageAction.class).getGraph(); assertTrue("Creation of graph should not cause loading of builds.", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); - + } - - public class ProjectTest extends Project implements TopLevelItem{ - - ProjectTest(ItemGroup group, String name){ - super(group, name); - onCreatedFromScratch(); - ItemListener.fireOnCreated(this); - } - + + public class ProjectTest extends Project implements TopLevelItem { + + ProjectTest(ItemGroup group, String name) { + super(group, name); + onCreatedFromScratch(); + ItemListener.fireOnCreated(this); + } + //@Override @Override - public Class getBuildClass(){ - return ProjectTestBuild.class; - } - + public Class getBuildClass() { + return ProjectTestBuild.class; + } + @Override - public ProjectTestBuild createExecutable() throws IOException{ + public ProjectTestBuild createExecutable() throws IOException { ProjectTestBuild build = new ProjectTestBuild(this); builds.put(getNextBuildNumber(), build); return build; } - - public ProjectTestBuild createExecutable(Calendar calendar) throws IOException{ + + public ProjectTestBuild createExecutable(Calendar calendar) throws IOException { ProjectTestBuild build = new ProjectTestBuild(this, calendar); build.number = this.assignBuildNumber(); builds.put(build.number, build); return build; } - + public TopLevelItemDescriptor getDescriptor() { throw new UnsupportedOperationException("Not supported yet."); } - - public void update(){ + + public void update() { this.updateTransientActions(); } - + @Override - public void save(){ + public void save() { //do not save fake project getRootDir().mkdirs(); } - } - - public class ProjectTestBuild extends Build{ + } + + public class ProjectTestBuild extends Build { + - public ProjectTestBuild(ProjectTest project) throws IOException { super(project); } - + public ProjectTestBuild(ProjectTest project, Calendar calendar) throws IOException { super(project, calendar); } @@ -237,6 +237,6 @@ public ProjectTestBuild(ProjectTest project, File buildDir) throws IOException { super(project, buildDir); } - } - + } + } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java index af109779..2178660f 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java @@ -21,14 +21,14 @@ * @author lucinka */ public class ProjectDiskUsageTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - - + + @Test @LocalData - public void testAllInfoLoaded() throws IOException{ + public void testAllInfoLoaded() throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); @@ -37,20 +37,20 @@ public void testAllInfoLoaded() throws IOException{ assertEquals("Set of DisUsageBuildInformation does not contains all builds of job.", 8, informations.size()); assertTrue("The test have to be rewritten because loaded builds is not less then all builds.", 8 > loadedBuilds); } - + @Test @LocalData - public void testFirstLoad() throws IOException{ + public void testFirstLoad() throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); Set informations = ((DiskUsageProperty) project.getProperty(DiskUsageProperty.class)).getDiskUsage().getBuildDiskUsage(false); assertEquals("Set of DisUsageBuildInformation should not contain information about builds because they are not loaded.", 0, informations.size()); } - + @Test @LocalData - public void testLoadingAllBuildInformationFromPreviousVersion(){ - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Builds information should be loaded.", 8, property.getDiskUsage().getBuildDiskUsage(true).size(), 0); + public void testLoadingAllBuildInformationFromPreviousVersion() { + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + assertEquals("Builds information should be loaded.", 8, property.getDiskUsage().getBuildDiskUsage(true).size(), 0); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index 27d72263..9a9d96de 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -57,11 +57,11 @@ public class WorkspaceDiskUsageCalculationThreadTest { @Rule public JenkinsRule j = new JenkinsRule(); - private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation) throws InterruptedException{ + private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; //wait until thread ends - for(Thread t : Thread.getAllStackTraces().keySet()){ - if(calculation.name.equals(t.getName())){ + for(Thread t: Thread.getAllStackTraces().keySet()) { + if(calculation.name.equals(t.getName())) { while(thread.isAlive()) { Thread.sleep(100); } @@ -69,42 +69,42 @@ private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation } } } - - private List readFileList(File file) throws FileNotFoundException, IOException{ + + private List readFileList(File file) throws FileNotFoundException, IOException { List files = new ArrayList(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); - while(line!=null){ + while(line != null) { files.add(new File(path + "/" + line)); line = content.readLine(); } return files; } - - private Long getSize(List files){ + + private Long getSize(List files) { Long length = 0l; - for(File file: files){ + for(File file: files) { length += file.length(); } - return length; + return length; } - - private Slave createSlave(String name, String remoteFS) throws Exception{ + + private Slave createSlave(String name, String remoteFS) throws Exception { DumbSlave slave = new DumbSlave(name, "dummy", - remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), - RetentionStrategy.NOOP, Collections.>emptyList()); - j.getInstance().addNode(slave); - while(slave.toComputer()==null || !slave.toComputer().isOnline()){ + remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), + RetentionStrategy.NOOP, Collections.>emptyList()); + j.getInstance().addNode(slave); + while(slave.toComputer() == null || !slave.toComputer().isOnline()) { Thread.sleep(100); } return slave; } - + @Test @LocalData - public void testExecute() throws IOException, InterruptedException, Exception{ + public void testExecute() throws IOException, InterruptedException, Exception { //turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); @@ -124,17 +124,17 @@ public void testExecute() throws IOException, InterruptedException, Exception{ Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project1).length(); size += getSize(readFileList(file2)) + slave2.getWorkspaceFor(project1).length(); file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); - Long size2 = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length() + slave2.getWorkspaceFor(project2).length(); + Long size2 = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length() + slave2.getWorkspaceFor(project2).length(); WorkspaceDiskUsageCalculationThread thread = new WorkspaceDiskUsageCalculationThread(); - if(thread.isExecuting()){ - waitUntilThreadEnds(thread); + if(thread.isExecuting()) { + waitUntilThreadEnds(thread); } thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of job workspace disk usage does not return right size.", size2, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } - + @Test @LocalData public void testExecuteMatrixProject() throws Exception { @@ -144,7 +144,7 @@ public void testExecuteMatrixProject() throws Exception { j.getInstance().setNumExecutors(0); Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); AxisList axes = new AxisList(); - TextAxis axis1 = new TextAxis("axis","axis1 axis2 axis3"); + TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); @@ -152,8 +152,8 @@ public void testExecuteMatrixProject() throws Exception { j.buildAndAssertSuccess(project1); MatrixProject project2 = j.jenkins.createProject(MatrixProject.class, "project2"); AxisList axes2 = new AxisList(); - TextAxis axis2 = new TextAxis("axis","axis1 axis2"); - axes2.add(axis2); + TextAxis axis2 = new TextAxis("axis", "axis1 axis2"); + axes2.add(axis2); project2.setAxes(axes2); project2.setAssignedNode(slave1); j.buildAndAssertSuccess(project2); @@ -162,25 +162,25 @@ public void testExecuteMatrixProject() throws Exception { project1.setAssignedNode(slave2); j.buildAndAssertSuccess(project1); WorkspaceDiskUsageCalculationThread thread = new WorkspaceDiskUsageCalculationThread(); - if(thread.isExecuting()){ - waitUntilThreadEnds(thread); + if(thread.isExecuting()) { + waitUntilThreadEnds(thread); } thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); slave1.toComputer().setTemporarilyOffline(false, null); //project 1 File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis1", "fileList"); - File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); - File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); + File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project1).length(); Long sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); Long sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); Long sizeAxis3 = getSize(readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis1", "fileList"); - fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis2", "fileList"); - fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote()+"/axis/axis3", "fileList"); + fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); size += getSize(readFileList(file)) + slave2.getWorkspaceFor(project1).length(); sizeAxis1 += getSize(readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); @@ -192,8 +192,8 @@ public void testExecuteMatrixProject() throws Exception { assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); //project 2 file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); - fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis1", "fileList"); - fileAxis2 = new File(slave1.getWorkspaceFor(project2).getRemote()+"/axis/axis2", "fileList"); + fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1", "fileList"); + fileAxis2 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2", "fileList"); size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length(); sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); @@ -201,11 +201,11 @@ public void testExecuteMatrixProject() throws Exception { //configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - + } - + @Test - public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ + public void testDoNotCalculateUnenabledDiskUsage() throws Exception { FreeStyleProject projectWithoutDiskUsage = j.getInstance().createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); FreeStyleBuild build = projectWithoutDiskUsage.createExecutable(); DiskUsageProjectActionFactory.DESCRIPTOR.disableWorkspacesDiskUsageCalculation(); @@ -214,10 +214,10 @@ public void testDoNotCalculateUnenabledDiskUsage() throws Exception{ assertEquals("Disk usage for build should not be counted.", 0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); } - + @Test @LocalData - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception{ + public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { WorkspaceDiskUsageCalculationThread testCalculation = new WorkspaceDiskUsageCalculationThread(); DiskUsageTestUtil.cancelCalculation(testCalculation); FreeStyleProject project = j.getInstance().createProject(FreeStyleProject.class, "project1"); @@ -226,9 +226,9 @@ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throw Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); prop.putSlaveWorkspace(slave1, slave1.getWorkspaceFor(project).getRemote()); Thread t = new Thread(testCalculation.getThreadName()){ - + @Override - public void run(){ + public void run() { try { Thread.sleep(10000); } catch (InterruptedException ex) { @@ -242,10 +242,10 @@ public void run(){ assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0, project.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); t.interrupt(); } - + @Test @LocalData - public void testDoNotBreakLazyLoading() throws Exception{ + public void testDoNotBreakLazyLoading() throws Exception { AbstractProject project = (AbstractProject) j.getInstance().getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); @@ -253,19 +253,19 @@ public void testDoNotBreakLazyLoading() throws Exception{ WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); assertTrue("WorkspaceCalculation should not cause loading of builds (only if the plugin is used for first time).", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); - + } - + @Test @LocalData - public void testDoNotCalculateExcludedJobs() throws Exception{ + public void testDoNotCalculateExcludedJobs() throws Exception { List excludes = new ArrayList(); excludes.add("excludedJob"); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); FreeStyleProject excludedJob = j.getInstance().createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.getInstance().createProject(FreeStyleProject.class, "incudedJob"); - if (Functions.isWindows()){ + if(Functions.isWindows()) { excludedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); includedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); } else { @@ -283,10 +283,10 @@ public void testDoNotCalculateExcludedJobs() throws Exception{ assertTrue("Disk usage for included project should be counted.", includedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize() > 0); excludes.clear(); } - + @Test @LocalData - public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception{ + public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { FreeStyleProject job = j.getInstance().createProject(FreeStyleProject.class, "project1"); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); job.setAssignedLabel(slave1.getSelfLabel()); @@ -300,19 +300,19 @@ public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception{ assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces()); assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces(), 0); } - + @TestExtension - public static class TestDiskUsageProperty extends DiskUsageProperty{ - + public static class TestDiskUsageProperty extends DiskUsageProperty { + @Override - public void putSlaveWorkspaceSize(Node node, String path, Long size){ + public void putSlaveWorkspaceSize(Node node, String path, Long size) { LOGGER.fine("workspace size " + size); try { Thread.sleep(10000); //make this operation longer } catch (InterruptedException ex) { Logger.getLogger(WorkspaceDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap(); } diff --git a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java index b115b1c6..386977bf 100644 --- a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java @@ -15,37 +15,37 @@ * @author Lucie Votypkova */ public class DiskUsagePostBuildCalculationTest { - + @Rule public JenkinsRule j = new JenkinsRule(); - + @Test - public void testDiskUsageIsCalculated() throws Exception{ + public void testDiskUsageIsCalculated() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); - + } - + @Test - public void testDiskUsageIsNotCalculatedTwoTimes() throws Exception{ + public void testDiskUsageIsNotCalculatedTwoTimes() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage called by listener should be skipped.", build.getLog(10).contains("Skipping calculation of disk usage, it was already done in post build step.")); } - + @Test - public void testDiskUsageCalculationForMatrixProject() throws Exception{ + public void testDiskUsageCalculationForMatrixProject() throws Exception { MatrixProject project = j.jenkins.createProject(MatrixProject.class, "project"); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); } - - + + } From 903eae101fe2bb98deab99c96f478ea8068134a4 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 00:54:14 +0000 Subject: [PATCH 041/158] Clean code using openrewrite SingleLineComments recipe --- .../disk_usage/BuildDiskUsageAction.java | 12 +++++----- .../BuildDiskUsageCalculationThread.java | 4 ++-- .../disk_usage/DiskUsageCalculation.java | 6 ++--- .../plugins/disk_usage/DiskUsagePlugin.java | 10 ++++---- .../DiskUsageProjectActionFactory.java | 2 +- .../plugins/disk_usage/DiskUsageProperty.java | 16 ++++++------- .../plugins/disk_usage/DiskUsageUtil.java | 14 +++++------ .../JobWithoutBuildsDiskUsageCalculation.java | 4 ++-- .../plugins/disk_usage/ProjectDiskUsage.java | 10 ++++---- .../disk_usage/ProjectDiskUsageAction.java | 6 ++--- .../WorkspaceDiskUsageCalculationThread.java | 4 ++-- .../disk_usage/DiskUsageCalculationTest.java | 24 +++++++++---------- .../BuildDiskUsageCalculationThreadTest.java | 12 +++++----- .../integration/DiskUsagePropertyTest.java | 20 ++++++++-------- .../integration/DiskUsageUtilTest.java | 18 +++++++------- .../JobDiskUsageCalculationThreadTest.java | 8 +++---- .../ProjectDiskUsageActionTest.java | 4 ++-- ...rkspaceDiskUsageCalculationThreadTest.java | 16 ++++++------- 18 files changed, 95 insertions(+), 95 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index 26f8a72e..22ed616d 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -21,7 +21,7 @@ * Disk usage information for a single build * @author dvrzalik */ -//TODO really implementsProminentProjectAction??? +// TODO really implementsProminentProjectAction??? @ExportedBean(defaultVisibility = 1) public class BuildDiskUsageAction implements ProminentProjectAction, BuildBadgeAction, RunAction2 { @@ -117,7 +117,7 @@ private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { } public Object readResolve() { - //for keeping backward compatibility + // for keeping backward compatibility if(diskUsage != null) { buildDiskUsage = diskUsage.buildUsage; Node node = build.getBuiltOn(); @@ -135,7 +135,7 @@ public Object readResolve() { @Override public void onAttached(Run r) { - //no action is needed + // no action is needed } @Override @@ -145,7 +145,7 @@ public void onLoad(Run r) { if(property == null) { return; } - //backward compatibility + // backward compatibility BuildDiskUsageAction action = null; for(Action a: build.getActions()) { if(a instanceof BuildDiskUsageAction) { @@ -156,7 +156,7 @@ public void onLoad(Run r) { } } if(action != null) { - //remove old action, now it is added by transition action factory + // remove old action, now it is added by transition action factory build.getActions().remove(action); try { build.save(); @@ -164,7 +164,7 @@ public void onLoad(Run r) { Logger.getLogger(BuildDiskUsageAction.class.getName()).log(Level.SEVERE, null, ex); } } - //Transient actions can be created even during deletion of job + // Transient actions can be created even during deletion of job if(property.getDiskUsageBuildInformation(build.getNumber()) == null && build.getRootDir().exists()) { property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); } diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index e8811bc7..11fd33d4 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -26,7 +26,7 @@ @Extension public class BuildDiskUsageCalculationThread extends DiskUsageCalculation { - //last scheduled task; + // last scheduled task; private static DiskUsageCalculation currentTask; public BuildDiskUsageCalculationThread() { @@ -54,7 +54,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(true)) { Map loadedBuilds = project._getRuns().getLoadedBuilds(); AbstractBuild build = loadedBuilds.get(information.getNumber()); - //do not calculat builds in progress + // do not calculat builds in progress if(build != null && build.isBuilding()) { continue; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 677f78a3..8a7add62 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -59,7 +59,7 @@ public String getThreadName() { public long scheduledLastInstanceExecutionTime() { try { CronTab tab = null; - if(getLastTask() == null || getLastTask().isCancelled()) { //not scheduled + if(getLastTask() == null || getLastTask().isCancelled()) { // not scheduled return 0l; } tab = getLastTask().getCronTab(); @@ -121,12 +121,12 @@ public long getRecurrencePeriod() { Calendar nextExecution = tab.ceil(now.getTimeInMillis()); long period = nextExecution.getTimeInMillis() - now.getTimeInMillis(); if(nextExecution.getTimeInMillis() - now.getTimeInMillis() <= 60000) { - period = period + 60000l; //add one minute to not shedule it during one minute one than once + period = period + 60000l; // add one minute to not shedule it during one minute one than once } return period; } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); - //it should not happen + // it should not happen return 1000 * 60 * 6; } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 277b4d43..478b99af 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -191,7 +191,7 @@ public Graph getOverallGraph() { } long maxValueWorkspace = Math.max(diskUsageNonSlaveWorkspaces, getCashedSlaveDiskUsageWorkspace()); List record = DiskUsageProjectActionFactory.DESCRIPTOR.getHistory(); - //First iteration just to get scale of the y-axis + // First iteration just to get scale of the y-axis for(DiskUsageOvearallGraphGenerator.DiskUsageRecord usage: record) { if(getConfiguration().getShowFreeSpaceForJobDirectory()) { maxValue = Math.max(maxValue, usage.getAllSpace()); @@ -219,7 +219,7 @@ public Graph getOverallGraph() { datasetW.addValue(((Long) usage.getNonSlaveWorkspacesUsage()) / baseWorkspace, "non slave workspaces", label); } - //add current state + // add current state if(getConfiguration().getShowFreeSpaceForJobDirectory()) { dataset.addValue(((Long) jobsDir.getTotalSpace()) / base, "space for jobs directory", "current"); } @@ -257,7 +257,7 @@ public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) public String getCountIntervalForBuilds() { long nextExecution = getBuildsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution <= 0) { //not scheduled + if(nextExecution <= 0) { // not scheduled nextExecution = getBuildsDiskUsageThread().getRecurrencePeriod(); } return DiskUsageUtil.formatTimeInMilisec(nextExecution); @@ -265,7 +265,7 @@ public String getCountIntervalForBuilds() { public String getCountIntervalForJobs() { long nextExecution = getJobsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution <= 0) { //not scheduled + if(nextExecution <= 0) { // not scheduled nextExecution = getJobsDiskUsageThread().getRecurrencePeriod(); } return DiskUsageUtil.formatTimeInMilisec(nextExecution); @@ -273,7 +273,7 @@ public String getCountIntervalForJobs() { public String getCountIntervalForWorkspaces() { long nextExecution = getWorkspaceDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); - if(nextExecution <= 0) { //not scheduled + if(nextExecution <= 0) { // not scheduled nextExecution = getWorkspaceDiskUsageThread().getRecurrencePeriod(); } return DiskUsageUtil.formatTimeInMilisec(nextExecution); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 0ab5a7b7..60eadc9d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -290,7 +290,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) { Logger.getLogger(DiskUsageProjectActionFactory.class.getName()).log(Level.SEVERE, null, ex); return false; } - //workspaceTimeOut = form.getInt("countInterval"); + // workspaceTimeOut = form.getInt("countInterval"); checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnSlave"); configureBuildsCalculation(form); configureJobsCalculation(form); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 71a93d43..9772cb42 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -134,7 +134,7 @@ public void setOwner(Job job) { diskUsage = new ProjectDiskUsage(); diskUsage.setProject(job); loadDiskUsage(); - //transfer old data + // transfer old data boolean modified = false; if(diskUsageWithoutBuilds != null) { diskUsage.diskUsageWithoutBuilds = diskUsageWithoutBuilds; @@ -273,7 +273,7 @@ public void checkWorkspaces(boolean force) { else { checkLoadedBuilds(); } - //only if it is wanted - can cost a quite long time to do it for all + // only if it is wanted - can cost a quite long time to do it for all if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnSlave() && owner instanceof TopLevelItem) { for(Node node: Jenkins.getInstance().getNodes()) { if(node.toComputer() != null && node.toComputer().isOnline()) { @@ -298,12 +298,12 @@ public void checkWorkspaces(boolean force) { if(node == null && nodeName.isEmpty()) { node = Jenkins.getInstance(); } - //delete name of slaves which do not exist - if(node == null) {//Jenkins master has empty name + // delete name of slaves which do not exist + if(node == null) {// Jenkins master has empty name iterator.remove(); } else { - //delete path which does not exists + // delete path which does not exists if(node != null && node.toComputer() != null && node.getChannel() != null) { Map workspaces = diskUsage.slaveWorkspacesUsage.get(nodeName); Iterator pathIterator = workspaces.keySet().iterator(); @@ -338,7 +338,7 @@ public Long getAllNonSlaveOrCustomWorkspaceSize() { else { node = Jenkins.getInstance().getNode(nodeName); } - if(node == null) { //slave does not exist + if(node == null) { // slave does not exist continue; } Map paths = getSlaveWorkspaceUsage().get(nodeName); @@ -388,7 +388,7 @@ public Long getAllWorkspaceSize() { Long size = 0l; for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node slave = Jenkins.getInstance().getNode(nodeName); - if(slave == null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {//slave does not exist + if(slave == null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {// slave does not exist continue; } Map paths = getSlaveWorkspaceUsage().get(nodeName); @@ -471,7 +471,7 @@ public void saveDiskUsage() { public void loadDiskUsage() { AbstractProject job = (AbstractProject) owner; diskUsage.load(); - //ensure that build was not removed without calling listener - badly removed, or badly saved (without build.xml) + // ensure that build was not removed without calling listener - badly removed, or badly saved (without build.xml) for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { File buildsDirectory = new File(owner.getRootDir(), "builds"); File build = new File(buildsDirectory, information.getId()); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 47dd9d5d..5d859307 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -288,7 +288,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener return; } try { - //count build.xml too + // count build.xml too build.save(); DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); listener.getLogger().println("Started calculate disk usage of build"); @@ -353,7 +353,7 @@ public static Long getFileSize(File f, List exceedFiles) throws IOExceptio for(File child: fileList) { if(exceedFiles.contains(child)) { continue; - } //do not count exceeded files + } // do not count exceeded files if(!isSymlink(child)) { size += getFileSize(child, exceedFiles); } @@ -431,8 +431,8 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr return; } DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - //Build disk usage has to be always recalculated to be kept up-to-date - //- artifacts might be kept only for the last build and users sometimes delete files manually as well. + // Build disk usage has to be always recalculated to be kept up-to-date + // - artifacts might be kept only for the last build and users sometimes delete files manually as well. long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList()); // if (build instanceof MavenModuleSetBuild) { // Collection> builds = ((MavenModuleSetBuild) build).getModuleBuilds().values(); @@ -448,7 +448,7 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr if(b.getId().equals(buildId)) { build = b; break; - //addBuildDiskUsageAction(build); + // addBuildDiskUsageAction(build); } } DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -468,7 +468,7 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr property.getDiskUsage().addBuildInformation(information, build); } else { - //should not happen + // should not happen AbstractBuild newLoadedBuild = (AbstractBuild) project._getRuns().getById(buildId); information = new DiskUsageBuildInformation(buildId, newLoadedBuild.getTimeInMillis(), newLoadedBuild.getNumber(), buildSize); property.getDiskUsage().addBuildInformation(information, build); @@ -518,7 +518,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I node = Jenkins.getInstance().getNode(nodeName); } if(node == null) { - //probably does not exists yet + // probably does not exists yet continue; } diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index dbe499f7..4bb09be8 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -25,7 +25,7 @@ @Extension public class JobWithoutBuildsDiskUsageCalculation extends DiskUsageCalculation { - //last scheduled task; + // last scheduled task; private static DiskUsageCalculation currentTask; @@ -45,7 +45,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(Object item: items) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - //do not count building project + // do not count building project if(project.isBuilding()) { continue; } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index add3120e..e1a0ae9a 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -108,8 +108,8 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size) { if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap(); } - //worksace with 0 are only initiative (are not counted yet) or does not exists - //no nexist workspaces are removed in method checkWorkspaces in class DiskUsageProperty + // worksace with 0 are only initiative (are not counted yet) or does not exists + // no nexist workspaces are removed in method checkWorkspaces in class DiskUsageProperty if(workspacesInfo.get(path) == null || size > 0l) { workspacesInfo.put(path, size); } @@ -142,7 +142,7 @@ public void loadAllBuilds() throws IOException { AbstractBuild build = (AbstractBuild) run; BuildDiskUsageAction toRemove = null; long buildOldDiskUsage = 0l; - //if not present, add + // if not present, add for(Action action: build.getActions()) { if(action instanceof BuildDiskUsageAction) { toRemove = (BuildDiskUsageAction) action; @@ -170,7 +170,7 @@ public void loadAllBuilds() throws IOException { // } // else{ // } - //DiskUsageUtil.addBuildDiskUsageAction(build); + // DiskUsageUtil.addBuildDiskUsageAction(build); } } allBuildsLoaded = true; @@ -187,7 +187,7 @@ public synchronized void load() { try { file.unmarshal(this); if(buildDiskUsage instanceof HashSet) { - //saved collection is not serialized in previous versions. + // saved collection is not serialized in previous versions. Set informations = new CopyOnWriteArraySet(); informations.addAll(buildDiskUsage); buildDiskUsage = informations; diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index c8a8f6a7..ca06cd8e 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -283,7 +283,7 @@ public Set getBuildsInformation() throws IOException * */ public Graph getGraph() throws IOException { - //TODO if(nothing_changed) return; + // TODO if(nothing_changed) return; List usages = new ArrayList(); long maxValue = 0; long maxValueWorkspace = 0; @@ -291,10 +291,10 @@ public Graph getGraph() throws IOException { maxValueWorkspace = Math.max(getAllCustomOrNonSlaveWorkspaces(), getAllSlaveWorkspaces()); Long jobRootDirDiskUsage = getJobRootDirDiskUsage(); maxValue = jobRootDirDiskUsage; - //First iteration just to get scale of the y-axis + // First iteration just to get scale of the y-axis ArrayList builds = new ArrayList(); builds.addAll(property.getDiskUsageOfBuilds()); - //do it in reverse order + // do it in reverse order for(int i = builds.size() - 1; i >= 0; i--) { DiskUsageBuildInformation build = builds.get(i); Long diskUsage = property.getDiskUsageOfBuild(build.getId()); diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index e3d04e54..77576e7c 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -25,7 +25,7 @@ @Extension public class WorkspaceDiskUsageCalculationThread extends DiskUsageCalculation { - //last scheduled task; + // last scheduled task; private static DiskUsageCalculation currentTask; public WorkspaceDiskUsageCalculationThread() { @@ -43,7 +43,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(Object item: items) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - //do not count workspace for running project + // do not count workspace for running project if(project.isBuilding()) { continue; } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 8500091d..aa1c3c75 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -35,7 +35,7 @@ public void testScheduledExecutionTime() throws Exception { // attribut currentTask should have value calculation TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", false); if(calculation.getLastTask() != null) { - //should not be any, but if cancel; + // should not be any, but if cancel; calculation.getLastTask().cancel(); } Long expectedNextExecution = calendar.getTimeInMillis(); @@ -43,7 +43,7 @@ public void testScheduledExecutionTime() throws Exception { Timer.get().schedule(calculation.getNewInstance(), calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); assertEquals("Scheduled time of disk usage calculation should be in 10 minutes", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); - //scheduled time should be changed if configuration of cron is changed + // scheduled time should be changed if configuration of cron is changed calendar.add(Calendar.MINUTE, 10); minute = calendar.get(Calendar.MINUTE); calculation.setCron(minute + " * * * *"); @@ -57,7 +57,7 @@ public void testScheduledExecutionTime() throws Exception { public void testGetRecurrencePeriod() { GregorianCalendar calendar = new GregorianCalendar(); - //for minutes + // for minutes int minute = calendar.get(Calendar.MINUTE); minute = minute + 2; calendar.add(Calendar.MINUTE, 2); @@ -67,10 +67,10 @@ public void testGetRecurrencePeriod() { Long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculation should be executed accurately in 2 minutes", expectedPeriod, period, 60000); - //for hours + // for hours calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); - calendar.add(Calendar.HOUR_OF_DAY, 2); //add 2 hours + calendar.add(Calendar.HOUR_OF_DAY, 2); // add 2 hours hour = calendar.get(Calendar.HOUR_OF_DAY); calendar.set(Calendar.MINUTE, 0); calculation = new TestDiskUsageCalculation("0 " + hour + " * * *", false); @@ -78,7 +78,7 @@ public void testGetRecurrencePeriod() { expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 hours.", expectedPeriod, period, 60000); - //for days + // for days calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, 2); int day = calendar.get(Calendar.DAY_OF_MONTH); @@ -87,17 +87,17 @@ public void testGetRecurrencePeriod() { expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 days.", expectedPeriod, period, 60000); - //for months + // for months calendar = new GregorianCalendar(); calendar.add(Calendar.MONTH, 2); - int month = calendar.get(Calendar.MONTH) + 1; //months are indexed from 0 + int month = calendar.get(Calendar.MONTH) + 1; // months are indexed from 0 calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + month + " *", false); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); - //day of week + // day of week calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_WEEK, 2); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1; @@ -117,13 +117,13 @@ public void testGetRecurrencePeriod() { */ @Test public void testReschedule() throws Exception { - //Trigger.timer = new Timer("Jenkins cron thread"); + // Trigger.timer = new Timer("Jenkins cron thread"); GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", true).getNewInstance(); - Timer.get().schedule(calculation, calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); //schedule it; + Timer.get().schedule(calculation, calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); // schedule it; calendar.add(Calendar.MINUTE, 10); minute = calendar.get(Calendar.MINUTE); calculation.setCron(minute + " * * * *"); @@ -149,7 +149,7 @@ public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { GregorianCalendar calendar = new GregorianCalendar(); int seconds = calendar.get(Calendar.SECOND); boolean firstLoop = true; - while((seconds > 55 && seconds < 59) || seconds == 0) { //have enought time for measure in current minute + while((seconds > 55 && seconds < 59) || seconds == 0) { // have enought time for measure in current minute if(firstLoop) { System.out.println("Waiting for appropriate time "); firstLoop = false; diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index 0811339e..47fd9d09 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -41,7 +41,7 @@ public class BuildDiskUsageCalculationThreadTest { private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; - //wait until thread ends + // wait until thread ends for(Thread t: Thread.getAllStackTraces().keySet()) { if(calculation.name.equals(t.getName())) { while(thread.isAlive()) { @@ -75,7 +75,7 @@ private Long getSize(List files) { @Test @LocalData public void testExecute() throws IOException, InterruptedException { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Map buildSizesProject1 = new TreeMap(); @@ -110,7 +110,7 @@ public void testExecute() throws IOException, InterruptedException { @Test @LocalData public void testExecuteMatrixProject() throws IOException, InterruptedException { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Map buildSizesProject2 = new TreeMap(); @@ -193,7 +193,7 @@ public TestFreeStyleProject(ItemGroup group, String name) { @Override public File getBuildDir() { - //is called during disk calculation, to be sure that calculation is in progress I make this operation longer + // is called during disk calculation, to be sure that calculation is in progress I make this operation longer try { Thread.sleep(10000); } catch (InterruptedException ex) { @@ -208,7 +208,7 @@ public void addBuild(FreeStyleBuild build) { @Override public void save() { - //do not want save + // do not want save } } @@ -234,7 +234,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception { public void testDoNotBreakLazyLoading() throws IOException, InterruptedException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - //method isBuilding() is used for determining disk usage and its calling load some builds + // method isBuilding() is used for determining disk usage and its calling load some builds project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("Test does not sense if there are all builds loaded, please rewrite it.", loadedBuilds < 8); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 221ea557..8bdd7cf8 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -65,7 +65,7 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { Long sizeOfProject = 7546l; Long sizeOfMatrixProject = 6800l; DiskUsageProperty projectProperty = project.getProperty(DiskUsageProperty.class); - //project.addProperty(projectProperty); + // project.addProperty(projectProperty); projectProperty.setDiskUsageWithoutBuilds(sizeOfProject); DiskUsageProperty matrixProjectProperty = matrixProject.getProperty(DiskUsageProperty.class); matrixProjectProperty.setDiskUsageWithoutBuilds(sizeOfMatrixProject); @@ -77,7 +77,7 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { c.addProperty(configurationProperty); configurationProperty.setDiskUsageWithoutBuilds(count * size1); matrixProjectTotalSize += count * size1; - //matrixProjectTotalSize += c.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); + // matrixProjectTotalSize += c.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); count++; } assertEquals("DiskUsageProperty for FreeStyleProject " + project.getDisplayName() + " returns wrong value its size without builds and including sub-projects.", sizeOfProject, project.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); @@ -86,7 +86,7 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { @Test public void testCheckWorkspaces() throws Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave slave1 = j.createOnlineSlave(); @@ -201,13 +201,13 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep Slave slave1 = j.createOnlineSlave(); Slave slave2 = j.createOnlineSlave(); File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName() + "/log"); - //DiskUsageTestUtil.createFileWithContent(workspaceSlave1); + // DiskUsageTestUtil.createFileWithContent(workspaceSlave1); File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); - //DiskUsageTestUtil.createFileWithContent(workspaceSlave2); + // DiskUsageTestUtil.createFileWithContent(workspaceSlave2); File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); - //DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave1); + // DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave1); File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); - //DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave2); + // DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave2); project.setAssignedLabel(slave3.getSelfLabel()); j.buildAndAssertSuccess(project); project.setCustomWorkspace(customWorkspaceSlave1.getParentFile().getAbsolutePath()); @@ -219,7 +219,7 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep j.buildAndAssertSuccess(project); Long customWorkspaceSlaveSize = customWorkspaceSlave1.length() + customWorkspaceSlave2.length() + customWorkspaceSlave1.getParentFile().length() + customWorkspaceSlave2.getParentFile().length(); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); - //take one slave offline + // take one slave offline slave1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); } @@ -248,7 +248,7 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception j.buildAndAssertSuccess(project); Long customWorkspaceSlaveSize = customWorkspaceSlave1.length() + customWorkspaceSlave2.length() + customWorkspaceSlave1.getParentFile().length() + customWorkspaceSlave2.getParentFile().length(); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); - //take one slave offline + // take one slave offline j.jenkins.setNumExecutors(0); assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); } @@ -528,7 +528,7 @@ private void checkForConcurrencyException(Exception exception) { fail("Checking of thread safety caused Exception which is not connected with thread safety problem."); } - //JENKINS-29143 + // JENKINS-29143 @Test public void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation() throws Exception { final FreeStyleProject project = j.createFreeStyleProject(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 8ca97906..fe420081 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -67,7 +67,7 @@ public void testCalculateDiskUsageForMatrixBuild() throws Exception { @LocalData public void testCalculateDiskUsageForJob() throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); - //all builds has to be loaded + // all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + project.getRootDir().length(); @@ -81,7 +81,7 @@ public void testCalculateDiskUsageForJob() throws Exception { @LocalData public void testCalculateDiskUsageForMatrixJob() throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); - //all builds has to be loaded + // all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + project.getRootDir().length(); @@ -105,7 +105,7 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception { @Test @LocalData public void testCalculateDiskUsageWorkspaceForProject() throws Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -135,7 +135,7 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception { @Test @LocalData public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory() throws Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); j.jenkins.setNumExecutors(0); @@ -172,8 +172,8 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - //next build - configuration are builded on next slave - //test if not active configuration are find and right counted + // next build - configuration are builded on next slave + // test if not active configuration are find and right counted // test if works with more complex configurations j.buildAndAssertSuccess(project1); for(MatrixConfiguration c: project1.getItems()) { @@ -195,8 +195,8 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - //matrix project is builded on the next slave - //test if new folder on slave2 is counted too + // matrix project is builded on the next slave + // test if new folder on slave2 is counted too project1.setAssignedNode(slave2); j.buildAndAssertSuccess(project1); file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); @@ -208,7 +208,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa @Test @LocalData public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() throws Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 7ef33988..4f9d3808 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -65,13 +65,13 @@ private Long getSize(List files) { @Test @LocalData public void testExecute() throws IOException, InterruptedException { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); - //we need all build information are loaded before counting + // we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); @@ -93,14 +93,14 @@ public void testExecute() throws IOException, InterruptedException { @Test @LocalData public void testMatrixProject() throws IOException, InterruptedException { - //turn off run listener + // turn off run listener DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Map matrixConfigurationsSize = new TreeMap(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); - //we need all build information are loaded before counting + // we need all build information are loaded before counting project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 7b1547ad..ffca0942 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -187,7 +187,7 @@ public class ProjectTest extends Project implemen ItemListener.fireOnCreated(this); } - //@Override + // @Override @Override public Class getBuildClass() { return ProjectTestBuild.class; @@ -217,7 +217,7 @@ public void update() { @Override public void save() { - //do not save fake project + // do not save fake project getRootDir().mkdirs(); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index 9a9d96de..b731c879 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -59,7 +59,7 @@ public class WorkspaceDiskUsageCalculationThreadTest { private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; - //wait until thread ends + // wait until thread ends for(Thread t: Thread.getAllStackTraces().keySet()) { if(calculation.name.equals(t.getName())) { while(thread.isAlive()) { @@ -105,7 +105,7 @@ private Slave createSlave(String name, String remoteFS) throws Exception { @Test @LocalData public void testExecute() throws IOException, InterruptedException, Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); @@ -138,7 +138,7 @@ public void testExecute() throws IOException, InterruptedException, Exception { @Test @LocalData public void testExecuteMatrixProject() throws Exception { - //turn off run listener + // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); j.getInstance().setNumExecutors(0); @@ -168,7 +168,7 @@ public void testExecuteMatrixProject() throws Exception { thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); slave1.toComputer().setTemporarilyOffline(false, null); - //project 1 + // project 1 File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); @@ -186,11 +186,11 @@ public void testExecuteMatrixProject() throws Exception { sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); sizeAxis3 += getSize(readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - //configurations + // configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - //project 2 + // project 2 file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1", "fileList"); fileAxis2 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2", "fileList"); @@ -198,7 +198,7 @@ public void testExecuteMatrixProject() throws Exception { sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - //configurations + // configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); @@ -308,7 +308,7 @@ public static class TestDiskUsageProperty extends DiskUsageProperty { public void putSlaveWorkspaceSize(Node node, String path, Long size) { LOGGER.fine("workspace size " + size); try { - Thread.sleep(10000); //make this operation longer + Thread.sleep(10000); // make this operation longer } catch (InterruptedException ex) { Logger.getLogger(WorkspaceDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } From 986aa1cd41c0db086cc2de5b060a4691e2f80226 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 00:55:27 +0000 Subject: [PATCH 042/158] Clean code using openrewrite Spaces recipe --- .../hudson/plugins/disk_usage/DiskUsageCalculationTest.java | 2 +- .../hudson/plugins/disk_usage/TestDiskUsageCalculation.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index aa1c3c75..f9672986 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -153,7 +153,7 @@ public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { if(firstLoop) { System.out.println("Waiting for appropriate time "); firstLoop = false; - }else { + } else { System.out.println("."); } Thread.sleep(1000); diff --git a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java index d77e0b1b..116acb34 100644 --- a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java +++ b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java @@ -78,7 +78,7 @@ public AperiodicWork getNewInstance() { } if(currentInstance != null) { currentInstance.cancel(); - }else { + } else { cancel(); } currentInstance = c; From 3eb8faee7dc93c66e902f8f6cbfebd1bf28274b6 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 10:12:59 +0000 Subject: [PATCH 043/158] Clean code using openrewrite CommonStaticAnalysis recipe --- .../disk_usage/BuildDiskUsageAction.java | 2 +- .../BuildDiskUsageCalculationThread.java | 5 ++--- .../disk_usage/DiskUsageBuildInformation.java | 2 ++ .../DiskUsageOvearallGraphGenerator.java | 6 ++--- .../plugins/disk_usage/DiskUsagePlugin.java | 13 +++++------ .../DiskUsageProjectActionFactory.java | 12 +++++----- .../plugins/disk_usage/DiskUsageProperty.java | 16 +++++++------- .../plugins/disk_usage/DiskUsageRecord.java | 10 ++++----- .../plugins/disk_usage/DiskUsageUtil.java | 20 +++++++++-------- .../JobWithoutBuildsDiskUsageCalculation.java | 5 ++--- .../plugins/disk_usage/ProjectDiskUsage.java | 18 +++++++-------- .../disk_usage/ProjectDiskUsageAction.java | 22 +++++++++---------- .../WorkspaceDiskUsageCalculationThread.java | 5 ++--- .../disk_usage/DiskUsageCalculationTest.java | 2 +- .../plugins/disk_usage/DiskUsageUtilTest.java | 4 ++-- .../disk_usage/TestDiskUsageCalculation.java | 4 ++-- .../integration/BuildDiskUsageActionTest.java | 12 +++++----- .../BuildDiskUsageCalculationThreadTest.java | 14 ++++++------ .../integration/DiskUsagePluginTest.java | 10 ++++----- .../integration/DiskUsagePropertyTest.java | 12 +++++----- .../integration/DiskUsageTestUtil.java | 4 ++-- .../integration/DiskUsageUtilTest.java | 2 +- .../JobDiskUsageCalculationThreadTest.java | 8 +++---- .../ProjectDiskUsageActionTest.java | 18 +++++++-------- ...rkspaceDiskUsageCalculationThreadTest.java | 8 +++---- 25 files changed, 117 insertions(+), 117 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index 22ed616d..645b3262 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -91,7 +91,7 @@ public String getBuildUsageString() { } private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { - Long buildsDiskUsage = 0l; + Long buildsDiskUsage = 0L; for(Object item: group.getItems()) { if(item instanceof ItemGroup) { buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) item); diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index 11fd33d4..82874c71 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -37,7 +37,7 @@ public BuildDiskUsageCalculationThread() { public void execute(TaskListener listener) throws IOException, InterruptedException { if(!isCancelled() && startExecution()) { try { - List items = new ArrayList(); + List items = new ArrayList<>(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); @@ -85,8 +85,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept public CronTab getCronTab() throws ANTLRException { String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); - CronTab tab = new CronTab(cron); - return tab; + return new CronTab(cron); } @Override diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index a4b9f78e..4683c78b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -15,6 +15,8 @@ */ public class DiskUsageBuildInformation implements Serializable, Comparable { + private static final long serialVersionUID = 1; + private static final DateFormat LEGACY_ID_FORMATTER = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); private String id; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 8df71590..d6099cf6 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -37,9 +37,9 @@ protected void doRun() throws Exception { public static class DiskUsageRecord extends DiskUsage { private static SimpleDateFormat sdf = new SimpleDateFormat("d/M"); Date date; - private Long jobsWithoutBuildsUsage = 0l; - private Long allSpace = 0l; - private Long diskUsageNonSlaveWorkspaces = 0l; + private Long jobsWithoutBuildsUsage = 0L; + private Long allSpace = 0L; + private Long diskUsageNonSlaveWorkspaces = 0L; public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 478b99af..688b4331 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -29,11 +29,11 @@ @Extension public class DiskUsagePlugin extends Plugin { - private Long diskUsageBuilds = 0l; - private Long diskUsageJobsWithoutBuilds = 0l; - private Long diskUsageWorkspaces = 0l; - private Long diskUsageLockedBuilds = 0l; - private Long diskUsageNonSlaveWorkspaces = 0l; + private Long diskUsageBuilds = 0L; + private Long diskUsageJobsWithoutBuilds = 0L; + private Long diskUsageWorkspaces = 0L; + private Long diskUsageLockedBuilds = 0L; + private Long diskUsageNonSlaveWorkspaces = 0L; public DiskUsagePlugin() { } @@ -132,8 +132,7 @@ public WorkspaceDiskUsageCalculationThread getWorkspaceDiskUsageThread() { * @return DiskUsage for given project (shortcut for the view). Never null. */ public ProjectDiskUsageAction getDiskUsage(Job project) { - ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); - return action; + return project.getAction(ProjectDiskUsageAction.class); } public String getDiskUsageInString(Long size) { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 60eadc9d..949ef237 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -52,7 +52,7 @@ public DescriptorImpl() { private boolean calculationWorkspace = true; - private boolean checkWorkspaceOnSlave = false; + private boolean checkWorkspaceOnSlave; private String email; @@ -66,12 +66,12 @@ public DescriptorImpl() { private boolean showFreeSpaceForJobDirectory = true; - private List excludedJobs = new ArrayList(); + private List excludedJobs = new ArrayList<>(); - private Long diskUsageBuilds = 0l; - private Long diskUsageJobsWithoutBuilds = 0l; - private Long diskUsageWorkspaces = 0l; - private Long diskUsageLockedBuilds = 0l; + private Long diskUsageBuilds = 0L; + private Long diskUsageJobsWithoutBuilds = 0L; + private Long diskUsageWorkspaces = 0L; + private Long diskUsageLockedBuilds = 0L; private boolean showGraph = true; private int historyLength = 183; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 9772cb42..ce8bef95 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -160,7 +160,7 @@ public void setOwner(Job job) { public void putSlaveWorkspace(Node node, String path) { Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); } if(!workspacesInfo.containsKey(path)) { workspacesInfo.put(path, 0l); @@ -180,7 +180,7 @@ public Map> getSlaveWorkspaceUsage() { public void putSlaveWorkspaceSize(Node node, String path, Long size) { Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); } workspacesInfo.put(path, size); getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); @@ -188,7 +188,7 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size) { } public Long getWorkspaceSize(Boolean containdedInWorkspace) { - Long size = 0l; + Long size = 0L; for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node node = Jenkins.getInstance().getNode(nodeName); String workspacePath = null; @@ -222,7 +222,7 @@ private void checkAllBuilds() { } Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); workspacesInfo.put(path.getRemote(), 0L); } else { @@ -248,7 +248,7 @@ private void checkLoadedBuilds() { } Map workspacesInfo = diskUsage.slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); workspacesInfo.put(path.getRemote(), 0L); } else { @@ -329,7 +329,7 @@ public void checkWorkspaces(boolean force) { } public Long getAllNonSlaveOrCustomWorkspaceSize() { - Long size = 0l; + Long size = 0L; for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node node = null; if(nodeName.isEmpty()) { @@ -385,7 +385,7 @@ private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path } public Long getAllWorkspaceSize() { - Long size = 0l; + Long size = 0L; for(String nodeName: getSlaveWorkspaceUsage().keySet()) { Node slave = Jenkins.getInstance().getNode(nodeName); if(slave == null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {// slave does not exist @@ -432,7 +432,7 @@ public Long getAllDiskUsageWithoutBuilds() { } private Long getDiskUsageWithoutBuildsAllSubItems(ItemGroup group) { - Long usage = 0l; + Long usage = 0L; for(Object item: group.getItems()) { if(item instanceof ItemGroup) { ItemGroup subGroup = (ItemGroup) item; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index 35ea481b..8ea0abdc 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -13,11 +13,11 @@ */ public class DiskUsageRecord { private Long date; - private Long diskUsageBuilds = 0l; - private Long diskUsageJobsWithoutBuilds = 0l; - private Long diskUsageWorkspaces = 0l; - private Long allSpace = 0l; - private Long diskUsageNonSlaveWorkspaces = 0l; + private Long diskUsageBuilds = 0L; + private Long diskUsageJobsWithoutBuilds = 0L; + private Long diskUsageWorkspaces = 0L; + private Long allSpace = 0L; + private Long diskUsageNonSlaveWorkspaces = 0L; public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { this.diskUsageBuilds = diskUsageBuilds; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 5d859307..64d47b80 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -189,7 +189,7 @@ public static void controlWorkspaceExceedSize(AbstractProject project) { builder.append("\n"); builder.append("List of workspaces:"); for(String slaveName: property.getSlaveWorkspaceUsage().keySet()) { - Long s = 0l; + Long s = 0L; for(Long l:property.getSlaveWorkspaceUsage().get(slaveName).values()) { s += l; } @@ -205,7 +205,7 @@ public static void controlWorkspaceExceedSize(AbstractProject project) { } public static List parseExcludedJobsFromString(String jobs) { - List list = new ArrayList(); + List list = new ArrayList<>(); String[] jobNames = jobs.split(","); for(String name: jobNames) { name = name.trim(); @@ -301,7 +301,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); } if(build.getWorkspace() != null) { - ArrayList exceededFiles = new ArrayList(); + ArrayList exceededFiles = new ArrayList<>(); AbstractProject project = build.getProject(); Node node = build.getBuiltOn(); if(project instanceof ItemGroup) { @@ -371,7 +371,7 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws return; } DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); - List exceededFiles = new ArrayList(); + List exceededFiles = new ArrayList<>(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { addProperty(project); @@ -433,7 +433,7 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); // Build disk usage has to be always recalculated to be kept up-to-date // - artifacts might be kept only for the last build and users sometimes delete files manually as well. - long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList()); + long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList<>()); // if (build instanceof MavenModuleSetBuild) { // Collection> builds = ((MavenModuleSetBuild) build).getModuleBuilds().values(); // for (List mavenBuilds : builds) { @@ -486,7 +486,7 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr } public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayList exceeded) throws IOException, InterruptedException { - Long diskUsage = 0l; + Long diskUsage = 0L; if(workspace.exists()) { try { diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); @@ -529,7 +529,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I FilePath workspace = new FilePath(node.toComputer().getChannel(), projectWorkspace); if(workspace.exists()) { Long diskUsage = property.getSlaveWorkspaceUsage().get(node.getNodeName()).get(workspace.getRemote()); - ArrayList exceededFiles = new ArrayList(); + ArrayList exceededFiles = new ArrayList<>(); if(project instanceof ItemGroup) { List projects = getAllProjects((ItemGroup) project); for(AbstractProject p: projects) { @@ -563,7 +563,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I } public static List getAllProjects(ItemGroup itemGroup) { - List items = new ArrayList(); + List items = new ArrayList<>(); for(Item item: itemGroup.getItems()) { if(item instanceof AbstractProject) { items.add((AbstractProject) item); @@ -580,6 +580,8 @@ public static List getAllProjects(ItemGroup ite */ public static class DiskUsageCallable implements Callable { + private static final long serialVersionUID = 1; + public static final Logger LOGGER = Logger .getLogger(DiskUsageCallable.class.getName()); @@ -593,7 +595,7 @@ public DiskUsageCallable(FilePath filePath, List exceedFilesPath) { public Long call() throws IOException { File f = new File(path.getRemote()); - List exceeded = new ArrayList(); + List exceeded = new ArrayList<>(); for(FilePath file: exceedFilesPath) { exceeded.add(new File(file.getRemote())); } diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 4bb09be8..a7fd21e5 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -38,7 +38,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); if(!isCancelled() && startExecution()) { try { - List items = new ArrayList(); + List items = new ArrayList<>(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); @@ -89,8 +89,7 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForJobs(); - CronTab tab = new CronTab(cron); - return tab; + return new CronTab(cron); } @Override diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index e1a0ae9a..61e99f45 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -36,9 +36,9 @@ public class ProjectDiskUsage implements Saveable { protected transient Job job; - protected Long diskUsageWithoutBuilds = 0l; - protected Map> slaveWorkspacesUsage = new ConcurrentHashMap>(); - private Set buildDiskUsage = new CopyOnWriteArraySet(); + protected Long diskUsageWithoutBuilds = 0L; + protected Map> slaveWorkspacesUsage = new ConcurrentHashMap<>(); + private Set buildDiskUsage = new CopyOnWriteArraySet<>(); private boolean allBuildsLoaded; @@ -59,7 +59,7 @@ public boolean isBuildsLoaded() { } public Set getBuildDiskUsage(boolean needAll) { - Set information = new HashSet(); + Set information = new HashSet<>(); AbstractProject p = (AbstractProject) job; if(needAll && !allBuildsLoaded) { try { @@ -106,7 +106,7 @@ private int numberOfBuildFolders() throws IOException { public void putSlaveWorkspaceSize(Node node, String path, Long size) { Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); } // worksace with 0 are only initiative (are not counted yet) or does not exists // no nexist workspaces are removed in method checkWorkspaces in class DiskUsageProperty @@ -133,7 +133,7 @@ public void loadAllBuilds() throws IOException { } AbstractProject project = (AbstractProject) job; List list = project.getBuilds(); - buildDiskUsage = new CopyOnWriteArraySet(); + buildDiskUsage = new CopyOnWriteArraySet<>(); for(Run run: list) { if(run instanceof AbstractBuild) { if(containsBuildWithId(run.getId())) { @@ -141,7 +141,7 @@ public void loadAllBuilds() throws IOException { } AbstractBuild build = (AbstractBuild) run; BuildDiskUsageAction toRemove = null; - long buildOldDiskUsage = 0l; + long buildOldDiskUsage = 0L; // if not present, add for(Action action: build.getActions()) { if(action instanceof BuildDiskUsageAction) { @@ -188,7 +188,7 @@ public synchronized void load() { file.unmarshal(this); if(buildDiskUsage instanceof HashSet) { // saved collection is not serialized in previous versions. - Set informations = new CopyOnWriteArraySet(); + Set informations = new CopyOnWriteArraySet<>(); informations.addAll(buildDiskUsage); buildDiskUsage = informations; } @@ -210,7 +210,7 @@ public synchronized void load() { * */ public void loadOldData() { - buildDiskUsage = new CopyOnWriteArraySet(); + buildDiskUsage = new CopyOnWriteArraySet<>(); List list = job.getBuilds(); for(Run run: list) { if(run instanceof AbstractBuild) { diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index ca06cd8e..f5d0c199 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -62,7 +62,7 @@ public Long getAllSlaveWorkspaces() { } public Long getAllCustomOrNonSlaveWorkspaces() { - Long diskUsage = 0l; + Long diskUsage = 0L; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property != null) { diskUsage += property.getAllNonSlaveOrCustomWorkspaceSize(); @@ -88,7 +88,7 @@ public Long getAllCustomOrNonSlaveWorkspaces() { * @return disk usage project and its sub-projects */ public Long getAllDiskUsageWorkspace() { - Long diskUsage = 0l; + Long diskUsage = 0L; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property != null) { diskUsage += property.getAllWorkspaceSize(); @@ -141,9 +141,9 @@ public Long getJobRootDirDiskUsage() { } private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date older, Date yonger) throws IOException { - Map diskUsage = new TreeMap(); - Long buildsDiskUsage = 0l; - Long locked = 0l; + Map diskUsage = new TreeMap<>(); + Long buildsDiskUsage = 0L; + Long locked = 0L; Long notLoaded = 0L; for(Object item: group.getItems()) { if(item instanceof ItemGroup) { @@ -214,10 +214,10 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); } - Map diskUsage = new TreeMap(); - Long buildsDiskUsage = 0l; - Long locked = 0l; - Long notLoaded = 0l; + Map diskUsage = new TreeMap<>(); + Long buildsDiskUsage = 0L; + Long locked = 0L; + Long notLoaded = 0L; if(project != null) { if(project instanceof ItemGroup) { ItemGroup group = (ItemGroup) project; @@ -284,7 +284,7 @@ public Set getBuildsInformation() throws IOException */ public Graph getGraph() throws IOException { // TODO if(nothing_changed) return; - List usages = new ArrayList(); + List usages = new ArrayList<>(); long maxValue = 0; long maxValueWorkspace = 0; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); @@ -292,7 +292,7 @@ public Graph getGraph() throws IOException { Long jobRootDirDiskUsage = getJobRootDirDiskUsage(); maxValue = jobRootDirDiskUsage; // First iteration just to get scale of the y-axis - ArrayList builds = new ArrayList(); + ArrayList builds = new ArrayList<>(); builds.addAll(property.getDiskUsageOfBuilds()); // do it in reverse order for(int i = builds.size() - 1; i >= 0; i--) { diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 77576e7c..9dc8e421 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -37,7 +37,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); if(!isCancelled() && startExecution()) { try { - List items = new ArrayList(); + List items = new ArrayList<>(); ItemGroup itemGroup = Jenkins.getInstance(); items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); for(Object item: items) { @@ -85,8 +85,7 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForWorkspaces(); - CronTab tab = new CronTab(cron); - return tab; + return new CronTab(cron); } @Override diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index f9672986..00263b70 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -143,7 +143,7 @@ public void testReschedule() throws Exception { public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { // Trigger.timer = new Timer("Jenkins cron thread"); // attribut currentTask should have value calculation - List scheduledInstances = new ArrayList(); + List scheduledInstances = new ArrayList<>(); TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); TestDiskUsageCalculation.startLoadInstancesHistory(scheduledInstances); GregorianCalendar calendar = new GregorianCalendar(); diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java index 10acf223..4033bf8e 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java @@ -12,7 +12,7 @@ public class DiskUsageUtilTest { @Test public void testGetSizeInBytes() { String sizeInString = "57 B"; - Long size = 57l; + Long size = 57L; Assert.assertEquals("Byte representation of size 57 B is wrong.", 57, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "5 KB"; size = 1024l * 5; @@ -33,7 +33,7 @@ public void testGetSizeInBytes() { @Test public void testGetSizeInString() { String sizeInString = "57 B"; - Long size = 57l; + Long size = 57L; Assert.assertEquals("String representation of size 57 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "5 KB"; size = 1024l * 5; diff --git a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java index 116acb34..20114130 100644 --- a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java +++ b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java @@ -21,9 +21,9 @@ public class TestDiskUsageCalculation extends BuildDiskUsageCalculationThread { private String cron; - public boolean executing = false; + public boolean executing; - private boolean sleep = false; + private boolean sleep; private static List instancesHistory; diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index 1ea2c6ed..eff4b9ab 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -40,9 +40,9 @@ public void testGetAllDiskUsage() throws Exception { MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild2 = matrixProject.getLastBuild(); - Long sizeofBuild = 7546l; - Long sizeOfMatrixBuild1 = 6800l; - Long sizeOfMatrixBuild2 = 14032l; + Long sizeofBuild = 7546L; + Long sizeOfMatrixBuild1 = 6800L; + Long sizeOfMatrixBuild2 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); @@ -78,7 +78,7 @@ public void getBuildUsageStringMatrixProject() throws Exception { j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild = matrixProject.getLastBuild(); matrixProject.setAxes(list); - Long kiloBytes = 2048l; + Long kiloBytes = 2048L; int count = 0; for(MatrixConfiguration c: matrixProject.getItems()) { AbstractBuild configurationBuild = c.getBuildByNumber(1); @@ -108,8 +108,8 @@ public void getBuildUsageStringFreeStyleProject() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); - Long bytes = 100l; - Long kiloBytes = 2048l; + Long bytes = 100L; + Long kiloBytes = 2048L; Long megaBytes = kiloBytes * 1024; Long gygaBytes = megaBytes * 1024; Long teraBytes = gygaBytes * 1024; diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index 47fd9d09..c318d905 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -53,7 +53,7 @@ private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) th } private List readFileList(File file) throws FileNotFoundException, IOException { - List files = new ArrayList(); + List files = new ArrayList<>(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); @@ -65,7 +65,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long lenght = 0l; + Long lenght = 0L; for(File file: files) { lenght += file.length(); } @@ -78,8 +78,8 @@ public void testExecute() throws IOException, InterruptedException { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject1 = new TreeMap(); - Map buildSizesProject2 = new TreeMap(); + Map buildSizesProject1 = new TreeMap<>(); + Map buildSizesProject2 = new TreeMap<>(); FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); for(AbstractBuild build: project.getBuilds()) { @@ -113,8 +113,8 @@ public void testExecuteMatrixProject() throws IOException, InterruptedException // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject2 = new TreeMap(); - Map matrixConfigurationBuildsSize = new TreeMap(); + Map buildSizesProject2 = new TreeMap<>(); + Map matrixConfigurationBuildsSize = new TreeMap<>(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); AbstractBuild matrixBuild = project.getBuildByNumber(1); @@ -216,7 +216,7 @@ public void save() { public void testDoNotCalculateExcludedJobs() throws Exception { FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); - List excludes = new ArrayList(); + List excludes = new ArrayList<>(); excludes.add(exludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); j.buildAndAssertSuccess(exludedJob); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 351d14f7..70b8d8a2 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -32,15 +32,15 @@ public void testRefreshGlobalInformation() throws IOException { FreeStyleBuild build1 = project.createExecutable(); FreeStyleBuild build2 = project.createExecutable(); FreeStyleBuild build3 = project.createExecutable(); - Long sizeofBuild1 = 7546l; - Long sizeofBuild2 = 6800l; - Long sizeofBuild3 = 14032l; + Long sizeofBuild1 = 7546L; + Long sizeofBuild2 = 6800L; + Long sizeofBuild3 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build1).setDiskUsage(sizeofBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(build2).setDiskUsage(sizeofBuild2); DiskUsageTestUtil.getBuildDiskUsageAction(build3).setDiskUsage(sizeofBuild3); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); - Long workspaceUsage = 20345l; - Long jobUsage = 5980l; + Long workspaceUsage = 20345L; + Long jobUsage = 5980L; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { property = new DiskUsageProperty(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 8bdd7cf8..a5c9bb03 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -62,8 +62,8 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { list.add(axis1); list.add(axis2); matrixProject.setAxes(list); - Long sizeOfProject = 7546l; - Long sizeOfMatrixProject = 6800l; + Long sizeOfProject = 7546L; + Long sizeOfMatrixProject = 6800L; DiskUsageProperty projectProperty = project.getProperty(DiskUsageProperty.class); // project.addProperty(projectProperty); projectProperty.setDiskUsageWithoutBuilds(sizeOfProject); @@ -132,7 +132,7 @@ public void getWorkspaceSizeTest() throws Exception { project.addProperty(prop); } prop.checkWorkspaces(); - Long workspaceSize = 7509l; + Long workspaceSize = 7509L; Map> diskUsage = prop.getSlaveWorkspaceUsage(); for(String name: diskUsage.keySet()) { Map slaveInfo = diskUsage.get(name); @@ -378,9 +378,9 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception { MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild2 = matrixProject.getLastBuild(); - Long sizeofBuild = 7546l; - Long sizeOfMatrixBuild1 = 6800l; - Long sizeOfMatrixBuild2 = 14032l; + Long sizeofBuild = 7546L; + Long sizeOfMatrixBuild1 = 6800L; + Long sizeOfMatrixBuild2 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index 0999eac0..fb1956b8 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -32,7 +32,7 @@ */ public class DiskUsageTestUtil { protected static List readFileList(File file) throws FileNotFoundException, IOException { - List files = new ArrayList(); + List files = new ArrayList<>(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); @@ -44,7 +44,7 @@ protected static List readFileList(File file) throws FileNotFoundException } protected static Long getSize(List files) { - Long lenght = 0l; + Long lenght = 0L; for(File file: files) { lenght += file.length(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index fe420081..34c21bda 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -148,7 +148,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa project1.setAssignedNode(slave1); j.buildAndAssertSuccess(project1); Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); - ArrayList slaves = new ArrayList(); + ArrayList slaves = new ArrayList<>(); slaves.add("slave2"); LabelAxis axis2 = new LabelAxis("label", slaves); axes.add(axis2); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 4f9d3808..fe5a7b1c 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -43,7 +43,7 @@ private void waitUntilThreadEnds(JobWithoutBuildsDiskUsageCalculation calculatio } private List readFileList(File file) throws FileNotFoundException, IOException { - List files = new ArrayList(); + List files = new ArrayList<>(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); @@ -55,7 +55,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long length = 0l; + Long length = 0L; for(File file: files) { length += file.length(); } @@ -97,7 +97,7 @@ public void testMatrixProject() throws IOException, InterruptedException { DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map matrixConfigurationsSize = new TreeMap(); + Map matrixConfigurationsSize = new TreeMap<>(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); // we need all build information are loaded before counting @@ -168,7 +168,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception { } FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); - List excludes = new ArrayList(); + List excludes = new ArrayList<>(); excludes.add(exludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); calculation.execute(TaskListener.NULL); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index ffca0942..a74629fb 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -52,9 +52,9 @@ public void testGetBuildsDiskUsage() throws Exception { MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild2 = matrixProject.getLastBuild(); - Long sizeofBuild = 7546l; - Long sizeOfMatrixBuild1 = 6800l; - Long sizeOfMatrixBuild2 = 14032l; + Long sizeofBuild = 7546L; + Long sizeOfMatrixBuild1 = 6800L; + Long sizeOfMatrixBuild2 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); @@ -94,9 +94,9 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild2 = matrixProject.getLastBuild(); - Long sizeofBuild = 7546l; - Long sizeOfMatrixBuild1 = 6800l; - Long sizeOfMatrixBuild2 = 14032l; + Long sizeofBuild = 7546L; + Long sizeOfMatrixBuild1 = 6800L; + Long sizeOfMatrixBuild2 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); @@ -144,9 +144,9 @@ public void getAllBuildDiskUsageFiltered() throws Exception { Date olderThan5months = filterCalendar.getTime(); filterCalendar.set(2013, 8, 19); Date olderThan3weeks = filterCalendar.getTime(); - Long sizeofBuild1 = 7546l; - Long sizeofBuild2 = 9546l; - Long sizeofBuild3 = 15546l; + Long sizeofBuild1 = 7546L; + Long sizeofBuild2 = 9546L; + Long sizeofBuild3 = 15546L; DiskUsageTestUtil.getBuildDiskUsageAction(build1).setDiskUsage(sizeofBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(build2).setDiskUsage(sizeofBuild2); DiskUsageTestUtil.getBuildDiskUsageAction(build3).setDiskUsage(sizeofBuild3); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index b731c879..96df59a9 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -71,7 +71,7 @@ private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation } private List readFileList(File file) throws FileNotFoundException, IOException { - List files = new ArrayList(); + List files = new ArrayList<>(); String path = file.getParentFile().getAbsolutePath(); BufferedReader content = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = content.readLine(); @@ -83,7 +83,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long length = 0l; + Long length = 0L; for(File file: files) { length += file.length(); @@ -259,7 +259,7 @@ public void testDoNotBreakLazyLoading() throws Exception { @Test @LocalData public void testDoNotCalculateExcludedJobs() throws Exception { - List excludes = new ArrayList(); + List excludes = new ArrayList<>(); excludes.add("excludedJob"); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); @@ -314,7 +314,7 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size) { } Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { - workspacesInfo = new ConcurrentHashMap(); + workspacesInfo = new ConcurrentHashMap<>(); } workspacesInfo.put(path, size); getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); From 0dc146859f808c46831250519fe00eadf238e58d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 24 Jan 2023 10:28:54 +0000 Subject: [PATCH 044/158] Clean code using openrewrite RemoveRedundantTypeCast recipe --- .../java/hudson/plugins/disk_usage/DiskUsagePlugin.java | 2 +- .../hudson/plugins/disk_usage/DiskUsageCalculationTest.java | 2 +- .../disk_usage/integration/DiskUsageBuildListenerTest.java | 4 ++-- .../disk_usage/integration/DiskUsagePropertyTest.java | 4 ++-- .../disk_usage/integration/ProjectDiskUsageActionTest.java | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 478b99af..c8051db0 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -47,7 +47,7 @@ public void refreshGlobalInformation() throws IOException { for(Item item: Jenkins.getInstance().getItems()) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - ProjectDiskUsageAction action = (ProjectDiskUsageAction) project.getAction(ProjectDiskUsageAction.class); + ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); diskUsageBuilds += action.getBuildsDiskUsage().get("all"); diskUsageWorkspaces += action.getAllDiskUsageWorkspace(); diskUsageJobsWithoutBuilds += action.getAllDiskUsageWithoutBuilds(); diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index f9672986..adff3efe 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -33,7 +33,7 @@ public void testScheduledExecutionTime() throws Exception { calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation - TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", false); + TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *", false); if(calculation.getLastTask() != null) { // should not be any, but if cancel; calculation.getLastTask().cancel(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index 0d23c725..eac45b46 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -32,7 +32,7 @@ public void testOnDeleted() throws Exception { j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); project.getBuildByNumber(2).delete(); assertNull("Build 2 was not removed from caches informations.", property.getDiskUsageBuildInformation(2)); assertNotNull("Disk usage property whoud contains cashed information about build 1.", property.getDiskUsageOfBuild(1)); @@ -48,7 +48,7 @@ public void testOnCompleted() throws Exception { project.getBuildersList().add(new Shell("echo ahoj > log.log")); } j.buildAndAssertSuccess(project); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); assertNotNull("Build information is cached.", property.getDiskUsageBuildInformation(1)); assertTrue("Build disk usage should be counted.", property.getDiskUsageOfBuild(1) > 0); assertTrue("Workspace of build should be counted.", property.getAllWorkspaceSize() > 0); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 8bdd7cf8..e3bd495e 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -398,8 +398,8 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception { matrixBuild2TotalSize += count * size2; count++; } - hudson.plugins.disk_usage.DiskUsageProperty freeStyleProjectProperty = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - DiskUsageProperty matrixProjectProperty = (DiskUsageProperty) matrixProject.getProperty(DiskUsageProperty.class); + hudson.plugins.disk_usage.DiskUsageProperty freeStyleProjectProperty = project.getProperty(DiskUsageProperty.class); + DiskUsageProperty matrixProjectProperty = matrixProject.getProperty(DiskUsageProperty.class); assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, freeStyleProjectProperty.getAllDiskUsageOfBuild(1)); assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(1)); assertEquals("BuildDiskUsageAction for build 2 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild2TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(2)); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index ffca0942..7a1633ed 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -130,9 +130,9 @@ public void getAllBuildDiskUsageFiltered() throws Exception { calendar1.set(2013, 9, 9); calendar2.set(2013, 8, 22); calendar3.set(2013, 5, 9); - ProjectTestBuild build1 = (ProjectTestBuild) project.createExecutable(calendar1); - ProjectTestBuild build2 = (ProjectTestBuild) project.createExecutable(calendar2); - ProjectTestBuild build3 = (ProjectTestBuild) project.createExecutable(calendar3); + ProjectTestBuild build1 = project.createExecutable(calendar1); + ProjectTestBuild build2 = project.createExecutable(calendar2); + ProjectTestBuild build3 = project.createExecutable(calendar3); Calendar filterCalendar = new GregorianCalendar(); filterCalendar.set(2013, 8, 30); Date youngerThan10days = filterCalendar.getTime(); From 237f7aeec2797af212cac0ec49e0d50c5d7c7b72 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 28 Jan 2023 00:19:02 +0000 Subject: [PATCH 045/158] Adds timeout to Jenkinsfile --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 22a78e9b..a84f0c4c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,5 @@ buildPlugin( + timeout: 30, useContainerAgent: true, configurations: [ [platform: 'linux', jdk: 17], From 0ebe96f0d620c66de1c5f32c38cbe2b178d8e02d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 28 Jan 2023 00:27:17 +0000 Subject: [PATCH 046/158] Removes commented code --- .../disk_usage/BuildDiskUsageAction.java | 2 +- .../BuildDiskUsageCalculationThread.java | 2 -- .../DiskUsageProjectActionFactory.java | 2 +- .../plugins/disk_usage/DiskUsageProperty.java | 14 ---------- .../plugins/disk_usage/DiskUsageUtil.java | 28 +------------------ .../plugins/disk_usage/ProjectDiskUsage.java | 16 ----------- .../disk_usage/DiskUsageCalculationTest.java | 11 +------- .../integration/DiskUsagePropertyTest.java | 8 ++---- .../ProjectDiskUsageActionTest.java | 1 - 9 files changed, 6 insertions(+), 78 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index 645b3262..3a678e83 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -146,7 +146,7 @@ public void onLoad(Run r) { return; } // backward compatibility - BuildDiskUsageAction action = null; + BuildDiskUsageAction action = null; for(Action a: build.getActions()) { if(a instanceof BuildDiskUsageAction) { action = (BuildDiskUsageAction) a; diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index 82874c71..d1fb8805 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -44,7 +44,6 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(Object item: items) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - // if (!project.isBuilding()) { DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { property = new DiskUsageProperty(); @@ -65,7 +64,6 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept logger.log(Level.WARNING, "Error when recording disk usage for " + project.getName(), e); } } - // } } } } catch (Exception ex) { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 949ef237..915a52d6 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -290,7 +290,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) { Logger.getLogger(DiskUsageProjectActionFactory.class.getName()).log(Level.SEVERE, null, ex); return false; } - // workspaceTimeOut = form.getInt("countInterval"); + checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnSlave"); configureBuildsCalculation(form); configureJobsCalculation(form); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index ce8bef95..052db230 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -171,7 +171,6 @@ public void putSlaveWorkspace(Node node, String path) { public Map> getSlaveWorkspaceUsage() { if(diskUsage.slaveWorkspacesUsage == null) { - // diskUsage.slaveWorkspacesUsage = new ConcurrentHashMap>(); checkWorkspaces(); } return diskUsage.slaveWorkspacesUsage; @@ -399,19 +398,6 @@ public Long getAllWorkspaceSize() { return size; } -// public Object readResolve() { -// //ensure that build was not removed without calling listener - badly removed, or badly saved (without build.xml) -// -// for(DiskUsageBuildInformation information : diskUsage.getBuildDiskUsage(false)){ -// File buildsDirectory = new File(owner.getRootDir(),"builds"); -// File build = new File(buildsDirectory,information.toString()); -// if(!build.exists()){ -// diskUsage.removeBuild(information); -// } -// } -// return this; -// } - public Long getDiskUsageWithoutBuilds() { if(diskUsage.diskUsageWithoutBuilds == null) { diskUsage.diskUsageWithoutBuilds = 0l; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 64d47b80..a6c4a50b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -407,24 +407,6 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws } } - -// public static void addBuildDiskUsageAction(AbstractBuild build){ -// BuildDiskUsageAction action = null; -// for(Action a: build.getActions()){ -// if(a instanceof BuildDiskUsageAction){ -// action = (BuildDiskUsageAction) a; -// break; -// } -// } -// if(action == null){ -// build.addAction(new BuildDiskUsageAction(build)); -// try { -// build.save(); -// } catch (IOException ex) { -// Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.SEVERE, null, ex); -// } -// } -// } public static void calculateDiskUsageForBuild(String buildId, AbstractProject project) throws IOException { if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { @@ -434,21 +416,13 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr // Build disk usage has to be always recalculated to be kept up-to-date // - artifacts might be kept only for the last build and users sometimes delete files manually as well. long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList<>()); - // if (build instanceof MavenModuleSetBuild) { -// Collection> builds = ((MavenModuleSetBuild) build).getModuleBuilds().values(); -// for (List mavenBuilds : builds) { -// for (MavenBuild mavenBuild : mavenBuilds) { -// calculateDiskUsageForBuild(mavenBuild); -// } -// } -// } + Collection loadedBuilds = project._getRuns().getLoadedBuilds().values(); AbstractBuild build = null; for(AbstractBuild b: loadedBuilds) { if(b.getId().equals(buildId)) { build = b; break; - // addBuildDiskUsageAction(build); } } DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 61e99f45..0f05db1b 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -160,17 +160,6 @@ public void loadAllBuilds() throws IOException { if(information.getSize() == 0l) { information.setSize(buildOldDiskUsage); } -// if(usage==null){ -// run.getActions().add(new BuildDiskUsageAction(build)); -// try { -// build.save(); -// } catch (IOException ex) { -// Logger.getLogger(ProjectDiskUsage.class.getName()).log(Level.SEVERE, null, ex); -// } -// } - // else{ - // } - // DiskUsageUtil.addBuildDiskUsageAction(build); } } allBuildsLoaded = true; @@ -195,11 +184,6 @@ public synchronized void load() { } catch (IOException e) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load " + file, e); } -// if(buildDiskUsage==null){ -// //seems like it needs load old data -// loadOldData(); -// } -// removeDeletedBuilds(); } /** diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 5461d4b6..00f63869 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -28,7 +28,6 @@ public class DiskUsageCalculationTest extends TestCase { */ @Test public void testScheduledExecutionTime() throws Exception { - // Trigger.timer = new Timer("Jenkins cron thread"); // it should be enought there is no need to start Jenkins GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -117,7 +116,6 @@ public void testGetRecurrencePeriod() { */ @Test public void testReschedule() throws Exception { - // Trigger.timer = new Timer("Jenkins cron thread"); GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -128,20 +126,13 @@ public void testReschedule() throws Exception { minute = calendar.get(Calendar.MINUTE); calculation.setCron(minute + " * * * *"); calculation.reschedule(); // should cancel this calculation and schedule new instance -// try{ -// System.out.println("new schedule"); -// calculation.doRun(); -// } -// catch(IllegalArgumentException e){ -// fail("Calculation should be canceled."); -// } + assertEquals("A new calculation should be scheduled with a new scheduled time.", calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000); } @Test public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { - // Trigger.timer = new Timer("Jenkins cron thread"); // attribut currentTask should have value calculation List scheduledInstances = new ArrayList<>(); TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 86461b34..69a0a44d 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -65,7 +65,6 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { Long sizeOfProject = 7546L; Long sizeOfMatrixProject = 6800L; DiskUsageProperty projectProperty = project.getProperty(DiskUsageProperty.class); - // project.addProperty(projectProperty); projectProperty.setDiskUsageWithoutBuilds(sizeOfProject); DiskUsageProperty matrixProjectProperty = matrixProject.getProperty(DiskUsageProperty.class); matrixProjectProperty.setDiskUsageWithoutBuilds(sizeOfMatrixProject); @@ -77,7 +76,6 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { c.addProperty(configurationProperty); configurationProperty.setDiskUsageWithoutBuilds(count * size1); matrixProjectTotalSize += count * size1; - // matrixProjectTotalSize += c.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); count++; } assertEquals("DiskUsageProperty for FreeStyleProject " + project.getDisplayName() + " returns wrong value its size without builds and including sub-projects.", sizeOfProject, project.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); @@ -200,14 +198,12 @@ public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Excep Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(), "SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave slave1 = j.createOnlineSlave(); Slave slave2 = j.createOnlineSlave(); + File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName() + "/log"); - // DiskUsageTestUtil.createFileWithContent(workspaceSlave1); File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); - // DiskUsageTestUtil.createFileWithContent(workspaceSlave2); File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); - // DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave1); File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); - // DiskUsageTestUtil.createFileWithContent(customWorkspaceSlave2); + project.setAssignedLabel(slave3.getSelfLabel()); j.buildAndAssertSuccess(project); project.setCustomWorkspace(customWorkspaceSlave1.getParentFile().getAbsolutePath()); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index b587a53a..11a1cdcf 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -187,7 +187,6 @@ public class ProjectTest extends Project implemen ItemListener.fireOnCreated(this); } - // @Override @Override public Class getBuildClass() { return ProjectTestBuild.class; From 2ede1e8ec185d8255744fa996c84ada571323ddc Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 28 Jan 2023 00:47:05 +0000 Subject: [PATCH 047/158] Migrate from junit 3 to junit 4 --- .../plugins/disk_usage/DiskUsageCalculationTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 5461d4b6..c68b4111 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -4,22 +4,21 @@ */ package hudson.plugins.disk_usage; -import hudson.triggers.Trigger; +import static org.junit.Assert.assertEquals; + import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import jenkins.util.Timer; -import junit.framework.TestCase; import org.junit.Test; /** * * @author lucinka */ -public class DiskUsageCalculationTest extends TestCase { +public class DiskUsageCalculationTest { /** * Depends on test testReschedule() - if testReshedule fails this test probably will fail too. From b46d258efd5bce76f1bf3c97096988f092cfb067 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 28 Jan 2023 17:05:25 +0000 Subject: [PATCH 048/158] Fix unit test that would be stuck in a loop If this unit test would start with seconds between 55 and 59 would never exit the loop. Changed to start the work in a thread and wait 1 minute and check that no new work was performed. --- .../disk_usage/DiskUsageCalculationTest.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 7f44b560..afdd3e07 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -6,6 +6,8 @@ import static org.junit.Assert.assertEquals; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; @@ -136,21 +138,17 @@ public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { List scheduledInstances = new ArrayList<>(); TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); TestDiskUsageCalculation.startLoadInstancesHistory(scheduledInstances); - GregorianCalendar calendar = new GregorianCalendar(); - int seconds = calendar.get(Calendar.SECOND); - boolean firstLoop = true; - while((seconds > 55 && seconds < 59) || seconds == 0) { // have enought time for measure in current minute - if(firstLoop) { - System.out.println("Waiting for appropriate time "); - firstLoop = false; - } else { - System.out.println("."); + + final var thread = new Thread(() -> { + try { + calculation.doRun(); + } catch (Throwable e) { + throw new RuntimeException(e); } - Thread.sleep(1000); - seconds = calendar.get(Calendar.SECOND); - } - calculation.doRun(); - Thread.sleep(2000); + }); + thread.start(); + Thread.sleep(Duration.of(1, ChronoUnit.MINUTES).toMillis()); + thread.join(); assertEquals("Method getRecurencePeriod should not able to schedule more than 1 task in 1 minute", 1, scheduledInstances.size()); TestDiskUsageCalculation.stopLoadInstancesHistory(); } From 3fa0b945b13f491b6c388806a016beaaf0a9cab7 Mon Sep 17 00:00:00 2001 From: Etienne Jouvin Date: Fri, 2 Oct 2015 00:26:06 +0200 Subject: [PATCH 049/158] Fix URL on images When display a project,, icons before Job, All bilds, Locked builds, All workspaces, Slave workspaces, Non-slave workspaces have a broken link. The root URL was missing, add ${resURL} as prefix in the attribute src, for node img. --- .../disk_usage/ProjectDiskUsageAction/jobMain.jelly | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly index 55b733cf..d322e36c 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly @@ -7,32 +7,32 @@
- + - + - + - + - + - + From 45fc2bf710ab6ae4ae08c6db7c2a19b2818ac71d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 28 Jan 2023 18:56:02 +0000 Subject: [PATCH 050/158] Replaces PNG and GIF with SVG and new Jenkins icons See: https://www.jenkins.io/doc/developer/views/icon-path-to-icon-class-migration/ --- .../plugins/disk_usage/DiskUsageManagement.java | 2 +- .../disk_usage/DiskUsagePlugin/index.jelly | 4 ++-- .../ProjectDiskUsageAction/jobMain.jelly | 16 ++++++++-------- src/main/webapp/icons/directory16.png | Bin 581 -> 0 bytes src/main/webapp/icons/diskusage16.png | Bin 756 -> 0 bytes src/main/webapp/icons/diskusage48.png | Bin 2911 -> 0 bytes 6 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 src/main/webapp/icons/directory16.png delete mode 100644 src/main/webapp/icons/diskusage16.png delete mode 100644 src/main/webapp/icons/diskusage48.png diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 24f5f870..97842688 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -23,7 +23,7 @@ public class DiskUsageManagement extends ManagementLink implements RootAction { public final String[] COLUMNS = new String[]{"Project name", "Builds", "Workspace", "JobDirectory (without builds)"}; public String getIconFileName() { - return "/plugin/disk-usage/icons/diskusage48.png"; + return "/plugin/disk-usage/icons/disk-usage.svg"; } public String getDisplayName() { diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly index e8023152..1efce6ee 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly @@ -7,7 +7,7 @@ --> - + @@ -23,7 +23,7 @@ -

${%Disk usage}

+

${%Disk usage}

${%Jobs}: ${it.getDiskUsageInString(it.getCashedGlobalJobsDiskUsage())}, ${%Builds}: ${it.getDiskUsageInString(it.getCashedGlobalBuildsDiskUsage())}, diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly index d322e36c..0a1f801d 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly @@ -1,38 +1,38 @@ - +

Directory iconDirectory icon ${%Job} ${from.getSizeInString(from.getJobRootDirDiskUsage())}
Directory iconDirectory icon ${%All builds} ${from.getSizeInString(from.getBuildsDiskUsage().get('all'))}
Directory iconDirectory icon ${%Locked builds} ${from.getSizeInString(from.getBuildsDiskUsage().get('locked'))}
Directory iconDirectory icon ${%All workspaces} ${from.getSizeInString(from.getAllDiskUsageWorkspace())}
Directory iconDirectory icon ${%Slave workspaces} ${from.getSizeInString(from.getAllSlaveWorkspaces())}
Directory iconDirectory icon ${%Non-slave workspaces} ${from.getSizeInString(from.getAllCustomOrNonSlaveWorkspaces())}
- + ${it.displayName}
- + - + - + - + - + - + diff --git a/src/main/webapp/icons/directory16.png b/src/main/webapp/icons/directory16.png deleted file mode 100644 index 65bd0bbdcb9005cb8929f06e25d9cb15a926366a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 581 zcmV-L0=oT)P)2|yPkE-3> z-8b(3_?ov1cYiV%432IDm|3sa>)kUm%nWx2;PmwLe!t&8>~uQMm(4k6LI`Cz9Dc0p zx&Tx;XIE7wlL@7i6(oef_V#uMc)NrGOsCVTl=7;s>w_zRjH+U0Ymj!k-P+vTq}6H> zV^0g%)=c>R8-N-3GD0!|F@>GqJ z%4)bdf_Rm4wwyD#6GYg!0ieZcvQf+lK>!v2)x`$$R0x3iqPe(Z=9oKK7jS;E^w*b55oWe`mg~7=)i^mlj0C%nT8s$wuo= zb!&(s!bMVmQn@?FCx!@o{yMsKc&XWJj=)i68(aN%$9JEC^W*#Yp8+C_MZ$~UM;0NT T9Al?300000NkvXXu0mjfM@0T3 diff --git a/src/main/webapp/icons/diskusage16.png b/src/main/webapp/icons/diskusage16.png deleted file mode 100644 index 49bbec96e1796844f6b495560786ffd35e7384e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 756 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 Date: Sun, 29 Jan 2023 22:26:30 +0000 Subject: [PATCH 051/158] Refresh UI with new Jenkins look and feel https://weekly.ci.jenkins.io/design-library/ --- .../DiskUsagePlugin/calculation.jelly | 79 ++++----- .../disk_usage/DiskUsagePlugin/index.jelly | 167 ++++++++++-------- 2 files changed, 126 insertions(+), 120 deletions(-) diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly index a1e1dffd..015a564f 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.jelly @@ -1,47 +1,42 @@ - - - ${%Interval.Message('builds', it.getCountIntervalForBuilds())}
- - - - ${%Counting of build disk usage is executing now.}
-
- -
-
-
+ + + ${%Interval.Message('builds', it.getCountIntervalForBuilds())} + + + ${%Counting of build disk usage is executing now.} + + + + + -
-
- -
- ${%Interval.Message('jobs', it.getCountIntervalForJobs())}
- - - - ${%Counting of job disk usage is executing now.}
-
- -
-
-
- -
-
- -
- ${%Interval.Message('workspaces', it.getCountIntervalForWorkspaces())}
- - - - ${%Counting of workspace disk usage is executing now.}
-
- -
-
-
+
+ + + ${%Interval.Message('jobs', it.getCountIntervalForJobs())} + + + ${%Counting of job disk usage is executing now.} + + + + + - +
+ +
+ ${%Interval.Message('workspaces', it.getCountIntervalForWorkspaces())} + + + ${%Counting of workspace disk usage is executing now.} + + + + + + +
\ No newline at end of file diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly index 1efce6ee..a1013157 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly @@ -1,94 +1,105 @@ - - - - + + + - + - - + + + +
+
+ ${%Disk Usage Trend} +
+
+ +
+
+ +

${%Disk usage}

-
-
- ${%Disk Usage Trend} -
-
- -
-
+
    +
  • ${%Jobs}:${it.getDiskUsageInString(it.getCashedGlobalJobsDiskUsage())}
  • +
  • ${%Builds}:${it.getDiskUsageInString(it.getCashedGlobalBuildsDiskUsage())}
  • +
  • ${%Locked builds}:${it.getDiskUsageInString(it.getCashedGlobalLockedBuildsDiskUsage())}
  • +
  • ${%All workspace}:${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())}
  • +
  • ${%Not current workspace}:${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())}
  • +
-

${%Disk usage}

- -

${%Jobs}: ${it.getDiskUsageInString(it.getCashedGlobalJobsDiskUsage())}, - ${%Builds}: ${it.getDiskUsageInString(it.getCashedGlobalBuildsDiskUsage())}, - ${%Locked builds}: ${it.getDiskUsageInString(it.getCashedGlobalLockedBuildsDiskUsage())}, - ${%All workspace}: ${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())}, - ${%Not current workspace}: ${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())}

- - - - - - - ${%Builds older than } - - - ${%Builds younger than } - - - - - -
Directory icon ${%Job} ${from.getSizeInString(from.getJobRootDirDiskUsage())}
Directory icon ${%All builds} ${from.getSizeInString(from.getBuildsDiskUsage().get('all'))}
Directory icon ${%Locked builds} ${from.getSizeInString(from.getBuildsDiskUsage().get('locked'))}
Directory icon ${%All workspaces} ${from.getSizeInString(from.getAllDiskUsageWorkspace())}
Directory icon ${%Slave workspaces} ${from.getSizeInString(from.getAllSlaveWorkspaces())}
Directory icon ${%Non-slave workspaces} ${from.getSizeInString(from.getAllCustomOrNonSlaveWorkspaces())}
- - - - - - + + + + +
+ ${%Builds older than } + + +
+
+ ${%Builds younger than } + + +
+
+ +
+
+ +
${%Project name} ${%Jobs} ${%Builds all} ${%Builds locked} ${%All workspace} ${%Not current slave workspace}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + - - - - - - - - - - - +
${%Project name}${%Jobs}${%Builds all}${%Builds locked}${%All workspace}${%Not current slave workspace}
${p.fullDisplayName}${it.getDiskUsageInString(buildDiskUsage.get('all') + diskUsage.getDiskUsageWithoutBuilds())}${it.getDiskUsageInString(buildDiskUsage.get('all'))}${it.getDiskUsageInString(buildDiskUsage.get('locked'))}${it.getDiskUsageInString(diskUsage.getAllDiskUsageWorkspace())}${it.getDiskUsageInString(diskUsage.getAllCustomOrNonSlaveWorkspaces())}
${p.fullDisplayName} ${it.getDiskUsageInString(buildDiskUsage.get('all') + diskUsage.getDiskUsageWithoutBuilds())}${it.getDiskUsageInString(buildDiskUsage.get('all'))}${it.getDiskUsageInString(buildDiskUsage.get('locked'))}${it.getDiskUsageInString(diskUsage.getAllDiskUsageWorkspace())}${it.getDiskUsageInString(diskUsage.getAllCustomOrNonSlaveWorkspaces())}${%Total}${it.getDiskUsageInString(it.getCashedGlobalJobsWithoutBuildsDiskUsage() + buildsAll)}${it.getDiskUsageInString(buildsAll)}${it.getDiskUsageInString(buildsLocked)}${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())}${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())}
${%Total} ${it.getDiskUsageInString(it.getCashedGlobalJobsWithoutBuildsDiskUsage() + buildsAll)}${it.getDiskUsageInString(buildsAll)}${it.getDiskUsageInString(buildsLocked)}${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())}${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())}
- -

+ - + \ No newline at end of file From 1b2e9bc61af0b917b448850689bbc6ac7900fdeb Mon Sep 17 00:00:00 2001 From: Thomas de Grenier de Latour Date: Tue, 13 Oct 2015 23:47:46 +0200 Subject: [PATCH 052/158] JENKINS-30934 - remove dubious Thread.sleep(60000) --- .../hudson/plugins/disk_usage/DiskUsageCalculation.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 8a7add62..ca56980b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -103,12 +103,6 @@ public void reschedule() { getLastTask().cancel(); } Timer.get().schedule(getNewInstance(), getRecurrencePeriod(), TimeUnit.MILLISECONDS); - - try { - Thread.sleep(60000); - } catch (InterruptedException ex) { - Logger.getLogger(DiskUsageCalculation.class.getName()).log(Level.SEVERE, null, ex); - } } public abstract CronTab getCronTab() throws ANTLRException; From 2a90382726bec19152e2640a3a82cc1f2f921a65 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 6 Feb 2023 00:05:15 +0000 Subject: [PATCH 053/158] JENKINS-64375 Disk Usage Plugin uses the deprecated "slave" terminology It doesn't replace all usages due to backwards compatibility fears. --- .../disk_usage/BuildDiskUsageAction.java | 2 +- .../DiskUsageOvearallGraphGenerator.java | 26 ++- .../plugins/disk_usage/DiskUsagePlugin.java | 52 ++++-- .../DiskUsageProjectActionFactory.java | 12 +- .../plugins/disk_usage/DiskUsageProperty.java | 65 ++++--- .../plugins/disk_usage/DiskUsageRecord.java | 10 ++ .../plugins/disk_usage/DiskUsageUtil.java | 26 ++- .../plugins/disk_usage/ProjectDiskUsage.java | 14 +- .../disk_usage/ProjectDiskUsageAction.java | 24 ++- .../disk_usage/DiskUsagePlugin/index.jelly | 8 +- .../global.jelly | 6 +- .../plugins/disk_usage/Messages.properties | 4 +- .../ProjectDiskUsageAction/jobMain.jelly | 8 +- .../integration/DiskUsagePluginTest.java | 2 +- .../integration/DiskUsagePropertyTest.java | 159 +++++++++--------- .../integration/DiskUsageTestUtil.java | 14 +- .../integration/DiskUsageUtilTest.java | 135 ++++++++------- ...rkspaceDiskUsageCalculationThreadTest.java | 134 ++++++++------- ...rojectWithConfigurationInSameDirectory.zip | Bin 52941 -> 52941 bytes ...spaceWhenReferenceFromJobDoesNotExists.zip | Bin 52941 -> 52941 bytes 20 files changed, 401 insertions(+), 300 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index 3a678e83..db620a4d 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -125,7 +125,7 @@ public Object readResolve() { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); AbstractProject project = build.getProject().getRootProject(); if(property != null && (project instanceof TopLevelItem)) { - property.putSlaveWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); + property.putAgentWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); } } diskUsage = null; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index d6099cf6..8cda782f 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -30,7 +30,7 @@ protected void doRun() throws Exception { File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); Long freeJobsDirSpace = jobsDir.getTotalSpace(); - DiskUsageProjectActionFactory.DESCRIPTOR.addHistory(new DiskUsageOvearallGraphGenerator.DiskUsageRecord(plugin.getCashedGlobalBuildsDiskUsage(), plugin.getGlobalSlaveDiskUsageWorkspace(), plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), freeJobsDirSpace, plugin.getCashedNonSlaveDiskUsageWorkspace())); + DiskUsageProjectActionFactory.DESCRIPTOR.addHistory(new DiskUsageOvearallGraphGenerator.DiskUsageRecord(plugin.getCashedGlobalBuildsDiskUsage(), plugin.getGlobalAgentDiskUsageWorkspace(), plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), freeJobsDirSpace, plugin.getCashedNonAgentDiskUsageWorkspace())); DiskUsageProjectActionFactory.DESCRIPTOR.save(); } @@ -39,14 +39,14 @@ public static class DiskUsageRecord extends DiskUsage { Date date; private Long jobsWithoutBuildsUsage = 0L; private Long allSpace = 0L; - private Long diskUsageNonSlaveWorkspaces = 0L; + private Long diskUsageNonAgentWorkspaces = 0L; - public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { + public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonAgentWorkspaces) { super(diskUsageBuilds, diskUsageWorkspaces); this.jobsWithoutBuildsUsage = diskUsageJobsWithoutBuilds; this.allSpace = allSpace; - this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; + this.diskUsageNonAgentWorkspaces = diskUsageNonAgentWorkspaces; date = new Date(){ private static final long serialVersionUID = 1L; @Override @@ -56,18 +56,28 @@ public String toString() { }; } + @Deprecated(forRemoval = true) public Long getNonSlaveWorkspacesUsage() { - if(diskUsageNonSlaveWorkspaces == null) { + return getNonAgentWorkspacesUsage(); + } + + public Long getNonAgentWorkspacesUsage() { + if(diskUsageNonAgentWorkspaces == null) { return 0l; } - return diskUsageNonSlaveWorkspaces; + return diskUsageNonAgentWorkspaces; } + @Deprecated(forRemoval = true) public Long getSlaveWorkspacesUsage() { - if(diskUsageNonSlaveWorkspaces == null) { + return getAgentWorkspacesUsage(); + } + + public Long getAgentWorkspacesUsage() { + if(diskUsageNonAgentWorkspaces == null) { return getWorkspacesDiskUsage(); } - return getWorkspacesDiskUsage() - diskUsageNonSlaveWorkspaces; + return getWorkspacesDiskUsage() - diskUsageNonAgentWorkspaces; } public Long getBuildsDiskUsage() { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index d7819e44..1789235e 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -2,14 +2,11 @@ import hudson.Extension; import hudson.Plugin; -import hudson.Util; import hudson.model.*; -import hudson.security.Permission; import hudson.util.Graph; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -33,7 +30,7 @@ public class DiskUsagePlugin extends Plugin { private Long diskUsageJobsWithoutBuilds = 0L; private Long diskUsageWorkspaces = 0L; private Long diskUsageLockedBuilds = 0L; - private Long diskUsageNonSlaveWorkspaces = 0L; + private Long diskUsageNonAgentWorkspaces = 0L; public DiskUsagePlugin() { } @@ -43,7 +40,7 @@ public void refreshGlobalInformation() throws IOException { diskUsageWorkspaces = 0l; diskUsageJobsWithoutBuilds = 0l; diskUsageLockedBuilds = 0l; - diskUsageNonSlaveWorkspaces = 0l; + diskUsageNonAgentWorkspaces = 0l; for(Item item: Jenkins.getInstance().getItems()) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; @@ -52,7 +49,7 @@ public void refreshGlobalInformation() throws IOException { diskUsageWorkspaces += action.getAllDiskUsageWorkspace(); diskUsageJobsWithoutBuilds += action.getAllDiskUsageWithoutBuilds(); diskUsageLockedBuilds += action.getBuildsDiskUsage().get("locked"); - diskUsageNonSlaveWorkspaces += action.getAllCustomOrNonSlaveWorkspaces(); + diskUsageNonAgentWorkspaces += action.getAllCustomOrNonAgentWorkspaces(); } } } @@ -77,12 +74,22 @@ public Long getCashedGlobalWorkspacesDiskUsage() { return diskUsageWorkspaces; } + @Deprecated(forRemoval = true) public Long getCashedNonSlaveDiskUsageWorkspace() { - return diskUsageNonSlaveWorkspaces; + return diskUsageNonAgentWorkspaces; } + public Long getCashedNonAgentDiskUsageWorkspace() { + return diskUsageNonAgentWorkspaces; + } + + @Deprecated(forRemoval = true) public Long getCashedSlaveDiskUsageWorkspace() { - return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; + return getCashedAgentDiskUsageWorkspace(); + } + + public Long getCashedAgentDiskUsageWorkspace() { + return diskUsageWorkspaces - diskUsageNonAgentWorkspaces; } public Long getGlobalBuildsDiskUsage() throws IOException { @@ -105,15 +112,24 @@ public Long getGlobalWorkspacesDiskUsage() throws IOException { return diskUsageWorkspaces; } - + @Deprecated(forRemoval = true) public Long getGlobalNonSlaveDiskUsageWorkspace() throws IOException { + return getGlobalNonAgentDiskUsageWorkspace(); + } + + public Long getGlobalNonAgentDiskUsageWorkspace() throws IOException { refreshGlobalInformation(); - return diskUsageNonSlaveWorkspaces; + return diskUsageNonAgentWorkspaces; } + @Deprecated(forRemoval = true) public Long getGlobalSlaveDiskUsageWorkspace() throws IOException { + return getGlobalAgentDiskUsageWorkspace(); + } + + public Long getGlobalAgentDiskUsageWorkspace() throws IOException { refreshGlobalInformation(); - return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; + return diskUsageWorkspaces - diskUsageNonAgentWorkspaces; } public BuildDiskUsageCalculationThread getBuildsDiskUsageThread() { @@ -188,7 +204,7 @@ public Graph getOverallGraph() { if(getConfiguration().getShowFreeSpaceForJobDirectory()) { maxValue = jobsDir.getTotalSpace(); } - long maxValueWorkspace = Math.max(diskUsageNonSlaveWorkspaces, getCashedSlaveDiskUsageWorkspace()); + long maxValueWorkspace = Math.max(diskUsageNonAgentWorkspaces, getCashedAgentDiskUsageWorkspace()); List record = DiskUsageProjectActionFactory.DESCRIPTOR.getHistory(); // First iteration just to get scale of the y-axis for(DiskUsageOvearallGraphGenerator.DiskUsageRecord usage: record) { @@ -196,8 +212,8 @@ public Graph getOverallGraph() { maxValue = Math.max(maxValue, usage.getAllSpace()); } maxValue = Math.max(maxValue, usage.getJobsDiskUsage()); - maxValueWorkspace = Math.max(maxValueWorkspace, usage.getSlaveWorkspacesUsage()); - maxValueWorkspace = Math.max(maxValueWorkspace, usage.getNonSlaveWorkspacesUsage()); + maxValueWorkspace = Math.max(maxValueWorkspace, usage.getAgentWorkspacesUsage()); + maxValueWorkspace = Math.max(maxValueWorkspace, usage.getNonAgentWorkspacesUsage()); } int floor = (int) DiskUsageUtil.getScale(maxValue); int floorWorkspace = (int) DiskUsageUtil.getScale(maxValueWorkspace); @@ -214,8 +230,8 @@ public Graph getOverallGraph() { } dataset.addValue(((Long) usage.getJobsDiskUsage()) / base, "all jobs", label); dataset.addValue(((Long) usage.getBuildsDiskUsage()) / base, "all builds", label); - datasetW.addValue(((Long) usage.getSlaveWorkspacesUsage()) / baseWorkspace, "slave workspaces", label); - datasetW.addValue(((Long) usage.getNonSlaveWorkspacesUsage()) / baseWorkspace, "non slave workspaces", label); + datasetW.addValue(((Long) usage.getAgentWorkspacesUsage()) / baseWorkspace, "agent workspaces", label); + datasetW.addValue(((Long) usage.getNonAgentWorkspacesUsage()) / baseWorkspace, "non agent workspaces", label); } // add current state @@ -224,8 +240,8 @@ public Graph getOverallGraph() { } dataset.addValue(((Long) getCashedGlobalJobsDiskUsage()) / base, "all jobs", "current"); dataset.addValue(((Long) getCashedGlobalBuildsDiskUsage()) / base, "all builds", "current"); - datasetW.addValue(((Long) getCashedSlaveDiskUsageWorkspace()) / baseWorkspace, "slave workspaces", "current"); - datasetW.addValue(((Long) getCashedNonSlaveDiskUsageWorkspace()) / baseWorkspace, "non slave workspaces", "current"); + datasetW.addValue(((Long) getCashedAgentDiskUsageWorkspace()) / baseWorkspace, "agent workspaces", "current"); + datasetW.addValue(((Long) getCashedNonAgentDiskUsageWorkspace()) / baseWorkspace, "non agent workspaces", "current"); return new DiskUsageGraph(dataset, unit, datasetW, unitWorkspace); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 915a52d6..2d411e12 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -151,14 +151,24 @@ public String getCountIntervalForWorkspaces() { return countIntervalWorkspace; } + @Deprecated(forRemoval = true) public boolean getCheckWorkspaceOnSlave() { + return getCheckWorkspaceOnAgent(); + } + + public boolean getCheckWorkspaceOnAgent() { return checkWorkspaceOnSlave; } + @Deprecated(forRemoval = true) public void setCheckWorkspaceOnSlave(boolean check) { checkWorkspaceOnSlave = check; } + public void setCheckWorkspaceOnAgent(boolean check) { + checkWorkspaceOnSlave = check; + } + public void setExcludedJobs(List excludedJobs) { this.excludedJobs = excludedJobs; } @@ -291,7 +301,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) { return false; } - checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnSlave"); + checkWorkspaceOnSlave = form.getBoolean("checkWorkspaceOnAgent"); configureBuildsCalculation(form); configureJobsCalculation(form); configureWorkspacesCalculation(form); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 052db230..8c884af6 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -13,7 +13,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -52,10 +51,10 @@ public void setDiskUsageWithoutBuilds(Long diskUsageWithoutBuilds) { public void remove(Node node, String path) { - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + Map workspacesInfo = getAgentWorkspaceUsage().get(node.getNodeName()); workspacesInfo.remove(path); if(workspacesInfo.isEmpty()) { - getSlaveWorkspaceUsage().remove(node.getNodeName()); + getAgentWorkspaceUsage().remove(node.getNodeName()); } saveDiskUsage(); } @@ -157,38 +156,53 @@ public void setOwner(Job job) { } } + @Deprecated(forRemoval = true) public void putSlaveWorkspace(Node node, String path) { - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + putAgentWorkspace(node, path); + } + + public void putAgentWorkspace(Node node, String path) { + Map workspacesInfo = getAgentWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); } if(!workspacesInfo.containsKey(path)) { workspacesInfo.put(path, 0l); } - getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); + getAgentWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); } + @Deprecated(forRemoval = true) public Map> getSlaveWorkspaceUsage() { + return getAgentWorkspaceUsage(); + } + + public Map> getAgentWorkspaceUsage() { if(diskUsage.slaveWorkspacesUsage == null) { checkWorkspaces(); } return diskUsage.slaveWorkspacesUsage; } + @Deprecated(forRemoval = true) public void putSlaveWorkspaceSize(Node node, String path, Long size) { - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + putAgentWorkspaceSize(node, path, size); + } + + public void putAgentWorkspaceSize(Node node, String path, Long size) { + Map workspacesInfo = getAgentWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); } workspacesInfo.put(path, size); - getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); + getAgentWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); } public Long getWorkspaceSize(Boolean containdedInWorkspace) { Long size = 0L; - for(String nodeName: getSlaveWorkspaceUsage().keySet()) { + for(String nodeName: getAgentWorkspaceUsage().keySet()) { Node node = Jenkins.getInstance().getNode(nodeName); String workspacePath = null; if(node instanceof Jenkins) { @@ -200,7 +214,7 @@ public Long getWorkspaceSize(Boolean containdedInWorkspace) { if(workspacePath == null) { continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); + Map paths = getAgentWorkspaceUsage().get(nodeName); for(String path: paths.keySet()) { if(containdedInWorkspace.equals(path.startsWith(workspacePath))) { size += paths.get(path); @@ -229,7 +243,7 @@ private void checkAllBuilds() { workspacesInfo.put(path.getRemote(), 0L); } } - getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); + getAgentWorkspaceUsage().put(node.getNodeName(), workspacesInfo); } } } @@ -255,7 +269,7 @@ private void checkLoadedBuilds() { workspacesInfo.put(path.getRemote(), 0L); } } - getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); + getAgentWorkspaceUsage().put(node.getNodeName(), workspacesInfo); } } } @@ -273,14 +287,14 @@ public void checkWorkspaces(boolean force) { checkLoadedBuilds(); } // only if it is wanted - can cost a quite long time to do it for all - if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnSlave() && owner instanceof TopLevelItem) { + if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnAgent() && owner instanceof TopLevelItem) { for(Node node: Jenkins.getInstance().getNodes()) { if(node.toComputer() != null && node.toComputer().isOnline()) { FilePath path = null; try { path = node.getWorkspaceFor((TopLevelItem) owner); if(path != null && path.exists() && (diskUsage.slaveWorkspacesUsage.get(node.getNodeName()) == null || !diskUsage.slaveWorkspacesUsage.get(node.getNodeName()).containsKey(path.getRemote()))) { - putSlaveWorkspace(node, path.getRemote()); + putAgentWorkspace(node, path.getRemote()); } } catch (Exception e) { @@ -297,7 +311,7 @@ public void checkWorkspaces(boolean force) { if(node == null && nodeName.isEmpty()) { node = Jenkins.getInstance(); } - // delete name of slaves which do not exist + // delete name of agents which do not exist if(node == null) {// Jenkins master has empty name iterator.remove(); } @@ -327,9 +341,14 @@ public void checkWorkspaces(boolean force) { saveDiskUsage(); } + @Deprecated(forRemoval = true) public Long getAllNonSlaveOrCustomWorkspaceSize() { + return getAllNonAgentOrCustomWorkspaceSize(); + } + + public Long getAllNonAgentOrCustomWorkspaceSize() { Long size = 0L; - for(String nodeName: getSlaveWorkspaceUsage().keySet()) { + for(String nodeName: getAgentWorkspaceUsage().keySet()) { Node node = null; if(nodeName.isEmpty()) { node = Jenkins.getInstance(); @@ -337,10 +356,10 @@ public Long getAllNonSlaveOrCustomWorkspaceSize() { else { node = Jenkins.getInstance().getNode(nodeName); } - if(node == null) { // slave does not exist + if(node == null) { // agent does not exist continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); + Map paths = getAgentWorkspaceUsage().get(nodeName); for(String path: paths.keySet()) { TopLevelItem item = null; if(owner instanceof TopLevelItem) { @@ -364,8 +383,8 @@ public Long getAllNonSlaveOrCustomWorkspaceSize() { private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path) { if(node instanceof Slave) { - Slave slave = (Slave) node; - return path.contains(slave.getRemoteFS()); + Slave agent = (Slave) node; + return path.contains(agent.getRemoteFS()); } else { if(node instanceof Jenkins) { @@ -385,12 +404,12 @@ private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path public Long getAllWorkspaceSize() { Long size = 0L; - for(String nodeName: getSlaveWorkspaceUsage().keySet()) { - Node slave = Jenkins.getInstance().getNode(nodeName); - if(slave == null && !nodeName.isEmpty() && !(slave instanceof Jenkins)) {// slave does not exist + for(String nodeName: getAgentWorkspaceUsage().keySet()) { + Node agent = Jenkins.getInstance().getNode(nodeName); + if(agent == null && !nodeName.isEmpty() && !(agent instanceof Jenkins)) {// agent does not exist continue; } - Map paths = getSlaveWorkspaceUsage().get(nodeName); + Map paths = getAgentWorkspaceUsage().get(nodeName); for(String path: paths.keySet()) { size += paths.get(path); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java index 8ea0abdc..1e034a5d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java @@ -35,11 +35,21 @@ public Long getBuildsDiskUsage() { return diskUsageBuilds; } + @Deprecated(forRemoval = true) public Long getNonSlaveWorkspacesUsage() { + return getNonAgentWorkspacesUsage(); + } + + public Long getNonAgentWorkspacesUsage() { return diskUsageNonSlaveWorkspaces; } + @Deprecated(forRemoval = true) public Long getSlaveWorkspacesUsage() { + return getAgentWorkspacesUsage(); + } + + public Long getAgentWorkspacesUsage() { return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index a6c4a50b..80bc6444 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -8,7 +8,6 @@ import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.Action; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Node; @@ -17,10 +16,6 @@ import hudson.tasks.Mailer; import java.io.File; import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; @@ -39,7 +34,6 @@ import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import jenkins.model.Jenkins; -import org.jenkinsci.remoting.Role; import org.jenkinsci.remoting.RoleChecker; /** @@ -188,13 +182,13 @@ public static void controlWorkspaceExceedSize(AbstractProject project) { builder.append("Workspaces of Job " + project.getDisplayName() + " have size " + size + "."); builder.append("\n"); builder.append("List of workspaces:"); - for(String slaveName: property.getSlaveWorkspaceUsage().keySet()) { + for(String agentName : property.getAgentWorkspaceUsage().keySet()) { Long s = 0L; - for(Long l:property.getSlaveWorkspaceUsage().get(slaveName).values()) { + for(Long l:property.getAgentWorkspaceUsage().get(agentName).values()) { s += l; } builder.append("\n"); - builder.append("Slave " + slaveName + " has workspace of job " + project.getDisplayName() + " with size " + getSizeString(s)); + builder.append("Agent " + agentName + " has workspace of job " + project.getDisplayName() + " with size " + getSizeString(s)); } try { sendEmail("Workspaces of Job " + project.getDisplayName() + " exceed size", builder.toString()); @@ -313,7 +307,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener p.addProperty(prop); } prop.checkWorkspaces(); - Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); + Map paths = prop.getAgentWorkspaceUsage().get(node.getNodeName()); if(paths != null && !paths.isEmpty()) { for(String path: paths.keySet()) { exceededFiles.add(new FilePath(node.getChannel(), path)); @@ -326,7 +320,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener Long startTimeOfWorkspaceCalculation = System.currentTimeMillis(); Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(), exceededFiles); listener.getLogger().println("Finished Calculation of disk usage of workspace in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfWorkspaceCalculation)); - property.putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); + property.putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); property.saveDiskUsage(); DiskUsageUtil.controlWorkspaceExceedSize(project); property.saveDiskUsage(); @@ -483,7 +477,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I } property.checkWorkspaces(); - for(String nodeName: property.getSlaveWorkspaceUsage().keySet()) { + for(String nodeName: property.getAgentWorkspaceUsage().keySet()) { Node node = null; if(nodeName.isEmpty()) { node = Jenkins.getInstance(); @@ -497,12 +491,12 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I } if(node.toComputer() != null && node.toComputer().getChannel() != null) { - Iterator iterator = property.getSlaveWorkspaceUsage().get(nodeName).keySet().iterator(); + Iterator iterator = property.getAgentWorkspaceUsage().get(nodeName).keySet().iterator(); while(iterator.hasNext()) { String projectWorkspace = iterator.next(); FilePath workspace = new FilePath(node.toComputer().getChannel(), projectWorkspace); if(workspace.exists()) { - Long diskUsage = property.getSlaveWorkspaceUsage().get(node.getNodeName()).get(workspace.getRemote()); + Long diskUsage = property.getAgentWorkspaceUsage().get(node.getNodeName()).get(workspace.getRemote()); ArrayList exceededFiles = new ArrayList<>(); if(project instanceof ItemGroup) { List projects = getAllProjects((ItemGroup) project); @@ -513,7 +507,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I p.addProperty(prop); } prop.checkWorkspaces(); - Map paths = prop.getSlaveWorkspaceUsage().get(node.getNodeName()); + Map paths = prop.getAgentWorkspaceUsage().get(node.getNodeName()); if(paths != null && !paths.isEmpty()) { for(String path: paths.keySet()) { exceededFiles.add(new FilePath(node.getChannel(), path)); @@ -523,7 +517,7 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I } diskUsage = calculateWorkspaceDiskUsageForPath(workspace, exceededFiles); if(diskUsage != null && diskUsage > 0) { - property.putSlaveWorkspaceSize(node, workspace.getRemote(), diskUsage); + property.putAgentWorkspaceSize(node, workspace.getRemote(), diskUsage); } controlWorkspaceExceedSize(project); } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 0f05db1b..1f38ab13 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -42,7 +42,12 @@ public class ProjectDiskUsage implements Saveable { private boolean allBuildsLoaded; + @Deprecated(forRemoval = true) public Map> getSlaveWorkspacesUsage() { + return getAgentWorkspacesUsage(); + } + + public Map> getAgentWorkspacesUsage() { return Maps.newHashMap(slaveWorkspacesUsage); } @@ -103,7 +108,12 @@ private int numberOfBuildFolders() throws IOException { return count; } + @Deprecated(forRemoval = true) public void putSlaveWorkspaceSize(Node node, String path, Long size) { + putAgentWorkspaceSize(node, path, size); + } + + public void putAgentWorkspaceSize(Node node, String path, Long size) { Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); @@ -153,7 +163,7 @@ public void loadAllBuilds() throws IOException { build.getActions().remove(toRemove); } if(build.getWorkspace() != null) { - putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); + putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); addBuildInformation(information, build); @@ -224,7 +234,7 @@ public void addBuildInformation(DiskUsageBuildInformation info, AbstractBuild bu if(!containsBuildWithId(info.getId())) { buildDiskUsage.add(info); if(build != null && build.getWorkspace() != null) { - putSlaveWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); + putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } } } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index f5d0c199..02ad47f3 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -57,15 +57,25 @@ public Long getDiskUsageWorkspace() { return property.getAllWorkspaceSize(); } + @Deprecated(forRemoval = true) public Long getAllSlaveWorkspaces() { - return getAllDiskUsageWorkspace() - getAllCustomOrNonSlaveWorkspaces(); + return getAllAgentWorkspaces(); } + public Long getAllAgentWorkspaces() { + return getAllDiskUsageWorkspace() - getAllCustomOrNonAgentWorkspaces(); + } + + @Deprecated(forRemoval = true) public Long getAllCustomOrNonSlaveWorkspaces() { + return getAllCustomOrNonAgentWorkspaces(); + } + + public Long getAllCustomOrNonAgentWorkspaces() { Long diskUsage = 0L; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property != null) { - diskUsage += property.getAllNonSlaveOrCustomWorkspaceSize(); + diskUsage += property.getAllNonAgentOrCustomWorkspaceSize(); } if(project instanceof ItemGroup) { ItemGroup group = (ItemGroup) project; @@ -74,7 +84,7 @@ public Long getAllCustomOrNonSlaveWorkspaces() { AbstractProject p = (AbstractProject) i; DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); if(prop != null) { - diskUsage += prop.getAllNonSlaveOrCustomWorkspaceSize(); + diskUsage += prop.getAllNonAgentOrCustomWorkspaceSize(); } } } @@ -288,7 +298,7 @@ public Graph getGraph() throws IOException { long maxValue = 0; long maxValueWorkspace = 0; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - maxValueWorkspace = Math.max(getAllCustomOrNonSlaveWorkspaces(), getAllSlaveWorkspaces()); + maxValueWorkspace = Math.max(getAllCustomOrNonAgentWorkspaces(), getAllAgentWorkspaces()); Long jobRootDirDiskUsage = getJobRootDirDiskUsage(); maxValue = jobRootDirDiskUsage; // First iteration just to get scale of the y-axis @@ -298,7 +308,7 @@ public Graph getGraph() throws IOException { for(int i = builds.size() - 1; i >= 0; i--) { DiskUsageBuildInformation build = builds.get(i); Long diskUsage = property.getDiskUsageOfBuild(build.getId()); - usages.add(new Object[]{build.getNumber(), getJobRootDirDiskUsage(), diskUsage, getAllSlaveWorkspaces(), getAllCustomOrNonSlaveWorkspaces()}); + usages.add(new Object[]{build.getNumber(), getJobRootDirDiskUsage(), diskUsage, getAllAgentWorkspaces(), getAllCustomOrNonAgentWorkspaces()}); maxValue = Math.max(maxValue, diskUsage); } @@ -317,9 +327,9 @@ public Graph getGraph() throws IOException { dataset.addValue(((Long) usage[2]) / base, Messages.DiskUsage_Graph_BuildDirectory(), label); dataset2.addValue(((Long) usage[3]) / workspaceBase, - Messages.DiskUsage_Graph_SlaveWorkspaces(), label); + Messages.DiskUsage_Graph_AgentWorkspaces(), label); dataset2.addValue(((Long) usage[4]) / workspaceBase, - Messages.DiskUsage_Graph_NonSlaveWorkspaces(), label); + Messages.DiskUsage_Graph_NonAgentWorkspaces(), label); } return new DiskUsageGraph(dataset, unit, dataset2, workspaceUnit); } diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly index a1013157..985ad5eb 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly @@ -27,7 +27,7 @@

  • ${%Builds}:${it.getDiskUsageInString(it.getCashedGlobalBuildsDiskUsage())}
  • ${%Locked builds}:${it.getDiskUsageInString(it.getCashedGlobalLockedBuildsDiskUsage())}
  • ${%All workspace}:${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())}
  • -
  • ${%Not current workspace}:${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())}
  • +
  • ${%Not current workspace}:${it.getDiskUsageInString(it.getCashedNonAgentDiskUsageWorkspace())}
  • @@ -64,7 +64,7 @@ ${%Builds all} ${%Builds locked} ${%All workspace} - ${%Not current slave workspace} + ${%Not current agent workspace} @@ -80,7 +80,7 @@ ${it.getDiskUsageInString(buildDiskUsage.get('all'))} ${it.getDiskUsageInString(buildDiskUsage.get('locked'))} ${it.getDiskUsageInString(diskUsage.getAllDiskUsageWorkspace())} - ${it.getDiskUsageInString(diskUsage.getAllCustomOrNonSlaveWorkspaces())} + ${it.getDiskUsageInString(diskUsage.getAllCustomOrNonAgentWorkspaces())} @@ -92,7 +92,7 @@ ${it.getDiskUsageInString(buildsAll)} ${it.getDiskUsageInString(buildsLocked)} ${it.getDiskUsageInString(it.getCashedGlobalWorkspacesDiskUsage())} - ${it.getDiskUsageInString(it.getCashedNonSlaveDiskUsageWorkspace())} + ${it.getDiskUsageInString(it.getCashedNonAgentDiskUsageWorkspace())} diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly index 711064c7..dbaa85da 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly @@ -94,13 +94,13 @@ - + - - + + diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages.properties b/src/main/resources/hudson/plugins/disk_usage/Messages.properties index e06083ff..ef6b1bb2 100755 --- a/src/main/resources/hudson/plugins/disk_usage/Messages.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages.properties @@ -6,5 +6,5 @@ DiskUsage.Graph.JobDiskUsageAxis=job, builds DiskUsage.Graph.WorkspaceDiskUsageAxis=workspaces DiskUsage.Graph.JobDirectory=job DiskUsage.Graph.BuildDirectory=builds -DiskUsage.Graph.SlaveWorkspaces=slave workspaces -DiskUsage.Graph.NonSlaveWorkspaces=non-slave workspaces +DiskUsage.Graph.AgentWorkspaces=agent workspaces +DiskUsage.Graph.NonAgentWorkspaces=non-agent workspaces diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly index 0a1f801d..3d64cc7d 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly @@ -28,13 +28,13 @@ - ${%Slave workspaces} - ${from.getSizeInString(from.getAllSlaveWorkspaces())} + ${%Agent workspaces} + ${from.getSizeInString(from.getAllAgentWorkspaces())} - ${%Non-slave workspaces} - ${from.getSizeInString(from.getAllCustomOrNonSlaveWorkspaces())} + ${%Non-agent workspaces} + ${from.getSizeInString(from.getAllCustomOrNonAgentWorkspaces())} diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 70b8d8a2..8f46d28c 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -47,7 +47,7 @@ public void testRefreshGlobalInformation() throws IOException { project.addProperty(property); } property.setDiskUsageWithoutBuilds(jobUsage); - property.putSlaveWorkspaceSize(j.jenkins, j.jenkins.getWorkspaceFor((TopLevelItem) project).getRemote(), workspaceUsage); + property.putAgentWorkspaceSize(j.jenkins, j.jenkins.getWorkspaceFor((TopLevelItem) project).getRemote(), workspaceUsage); plugin.refreshGlobalInformation(); assertEquals("Global build diskUsage should be refreshed.", sizeofBuild1 + sizeofBuild2 + sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0); assertEquals("Global job diskUsage should be refreshed.", jobUsage, plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), 0); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 69a0a44d..4c9e6045 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -5,7 +5,6 @@ import hudson.tasks.BatchFile; import java.util.ConcurrentModificationException; import java.util.GregorianCalendar; -import hudson.model.FreeStyleBuild; import hudson.util.XStream2; import hudson.model.AbstractBuild; import hudson.matrix.MatrixBuild; @@ -87,12 +86,12 @@ public void testCheckWorkspaces() throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = j.createOnlineSlave(); - Slave slave2 = j.createOnlineSlave(); + Slave agent1 = j.createOnlineSlave(); + Slave agent2 = j.createOnlineSlave(); FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - project.setAssignedLabel(slave1.getSelfLabel()); + project.setAssignedLabel(agent1.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setAssignedLabel(slave2.getSelfLabel()); + project.setAssignedLabel(agent2.getSelfLabel()); j.buildAndAssertSuccess(project); project.getBuildByNumber(1).delete(); DiskUsageProperty prop = project.getProperty(DiskUsageProperty.class); @@ -101,26 +100,30 @@ public void testCheckWorkspaces() throws Exception { project.addProperty(prop); } prop.checkWorkspaces(); - Set nodes = prop.getSlaveWorkspaceUsage().keySet(); - assertTrue("DiskUsage property should contains slave " + slave2.getDisplayName() + " in slaveWorkspaceUsage.", nodes.contains(slave2.getNodeName())); - assertFalse("DiskUsage property should not contains slave " + slave1.getDisplayName() + " in slaveWorkspaceUsage when detection of user workspace withour reference from project is not set.", nodes.contains(slave1.getNodeName())); - j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnSlave(true); + Set nodes = prop.getAgentWorkspaceUsage().keySet(); + assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( + agent2.getNodeName())); + assertFalse("DiskUsage property should not contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace withour reference from project is not set.", nodes.contains( + agent1.getNodeName())); + j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(true); prop.checkWorkspaces(); - assertTrue("DiskUsage property should contains slave " + slave2.getDisplayName() + " in slaveWorkspaceUsage.", nodes.contains(slave2.getNodeName())); - assertTrue("DiskUsage property should contains slave " + slave1.getDisplayName() + " in slaveWorkspaceUsage when detection of user workspace withour reference from project is set.", nodes.contains(slave1.getNodeName())); - j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnSlave(false); + assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( + agent2.getNodeName())); + assertTrue("DiskUsage property should contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace withour reference from project is set.", nodes.contains( + agent1.getNodeName())); + j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(false); } @Test public void getWorkspaceSizeTest() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); - project.setAssignedLabel(slave1.getSelfLabel()); + project.setAssignedLabel(agent1.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setAssignedLabel(slave2.getSelfLabel()); + project.setAssignedLabel(agent2.getSelfLabel()); j.buildAndAssertSuccess(project); project.setCustomWorkspace(j.jenkins.getRootDir().getAbsolutePath() + "/project-custom-workspace"); j.buildAndAssertSuccess(project); @@ -131,36 +134,37 @@ public void getWorkspaceSizeTest() throws Exception { } prop.checkWorkspaces(); Long workspaceSize = 7509L; - Map> diskUsage = prop.getSlaveWorkspaceUsage(); + Map> diskUsage = prop.getAgentWorkspaceUsage(); for(String name: diskUsage.keySet()) { - Map slaveInfo = diskUsage.get(name); - for(String path: slaveInfo.keySet()) { - slaveInfo.put(path, workspaceSize); + Map agentInfo = diskUsage.get(name); + for(String path: agentInfo.keySet()) { + agentInfo.put(path, workspaceSize); } } - assertEquals("DiskUsage workspaces which is configured as slave workspace is wrong.", workspaceSize * 2, prop.getWorkspaceSize(true), 0); - assertEquals("DiskUsage workspaces which is not configured as slave workspace is wrong.", workspaceSize, prop.getWorkspaceSize(false), 0); + assertEquals("DiskUsage workspaces which is configured as agent workspace is wrong.", workspaceSize * 2, prop.getWorkspaceSize(true), 0); + assertEquals("DiskUsage workspaces which is not configured as agent workspace is wrong.", workspaceSize, prop.getWorkspaceSize(false), 0); } @Test - public void testchcekWorkspacesIfSlaveIsDeleted() throws Exception { + public void testcheckWorkspacesIfAgentIsDeleted() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); - Slave slave1 = j.createOnlineSlave(); - Slave slave2 = j.createOnlineSlave(); - slave1.getWorkspaceRoot().mkdirs(); - slave2.getWorkspaceRoot().mkdirs(); + Slave agent1 = j.createOnlineSlave(); + Slave agent2 = j.createOnlineSlave(); + agent1.getWorkspaceRoot().mkdirs(); + agent2.getWorkspaceRoot().mkdirs(); FilePath path = j.jenkins.getWorkspaceFor(project); path.mkdirs(); - property.putSlaveWorkspaceSize(j.jenkins, path.getRemote(), 10495l); - property.putSlaveWorkspaceSize(slave1, slave1.getRemoteFS(), 5670l); - property.putSlaveWorkspaceSize(slave2, slave2.getRemoteFS(), 7987l); - j.jenkins.removeNode(slave2); + property.putAgentWorkspaceSize(j.jenkins, path.getRemote(), 10495l); + property.putAgentWorkspaceSize(agent1, agent1.getRemoteFS(), 5670l); + property.putAgentWorkspaceSize(agent2, agent2.getRemoteFS(), 7987l); + j.jenkins.removeNode(agent2); property.checkWorkspaces(); - assertFalse("Disk usage property should not contains slave which does not exist.", property.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); - assertTrue("Disk usage property should contains slave1.", property.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse("Disk usage property should not contains agent which does not exist.", property.getAgentWorkspaceUsage().containsKey( + agent2.getNodeName())); + assertTrue("Disk usage property should contains agent1.", property.getAgentWorkspaceUsage().containsKey(agent1.getNodeName())); + assertTrue("Disk usage property should contains jenkins master.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); } @Test @@ -168,85 +172,86 @@ public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); - Slave slave1 = j.createOnlineSlave(); - Slave slave2 = j.createOnlineSlave(); - slave1.getWorkspaceRoot().mkdirs(); - slave2.getWorkspaceRoot().mkdirs(); + Slave agent1 = j.createOnlineSlave(); + Slave agent2 = j.createOnlineSlave(); + agent1.getWorkspaceRoot().mkdirs(); + agent2.getWorkspaceRoot().mkdirs(); FilePath path = j.jenkins.getWorkspaceFor(project); path.mkdirs(); - property.putSlaveWorkspaceSize(j.jenkins, path.getRemote(), 10495l); - property.putSlaveWorkspaceSize(slave1, slave1.getRemoteFS() + "/project", 5670l); - property.putSlaveWorkspaceSize(slave2, slave2.getRemoteFS(), 7987l); + property.putAgentWorkspaceSize(j.jenkins, path.getRemote(), 10495l); + property.putAgentWorkspaceSize(agent1, agent1.getRemoteFS() + "/project", 5670l); + property.putAgentWorkspaceSize(agent2, agent2.getRemoteFS(), 7987l); property.checkWorkspaces(); - assertFalse("Disk usage property should not contains slave which does not have any workspace for its project.", property.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); - assertTrue("Disk usage property should contains slave2.", property.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse("Disk usage property should not contains agent which does not have any workspace for its project.", property.getAgentWorkspaceUsage().containsKey( + agent1.getNodeName())); + assertTrue("Disk usage property should contains agent2.", property.getAgentWorkspaceUsage().containsKey(agent2.getNodeName())); + assertTrue("Disk usage property should contains jenkins master.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); path.delete(); property.checkWorkspaces(); - assertFalse("Disk usage property should contains jenkins master, because workspace for its project was deleted.", property.getSlaveWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse("Disk usage property should contains jenkins master, because workspace for its project was deleted.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); } @Test - public void testGetAllNonSlaveOrCustomWorkspaceSizeWithOnlySlaves() throws Exception { + public void testGetAllNonAgentOrCustomWorkspaceSizeWithOnlyAgents() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); } else { project.getBuildersList().add(new Shell("echo hello > log")); } - Slave slave3 = DiskUsageTestUtil.createSlave("slave3", new File(j.jenkins.getRootDir(), "SlaveWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave1 = j.createOnlineSlave(); - Slave slave2 = j.createOnlineSlave(); + Slave agent3 = DiskUsageTestUtil.createAgent("agent3", new File(j.jenkins.getRootDir(), "AgentWorkspace").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = j.createOnlineSlave(); + Slave agent2 = j.createOnlineSlave(); - File workspaceSlave1 = new File(slave3.getRemoteFS(), project.getName() + "/log"); - File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); - File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); - File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); + File workspaceAgent1 = new File(agent3.getRemoteFS(), project.getName() + "/log"); + File workspaceAgent2 = new File(agent1.getRemoteFS(), project.getName() + "/log"); + File customWorkspaceAgent1 = new File(j.jenkins.getRootDir(), "custom2/log"); + File customWorkspaceAgent2 = new File(j.jenkins.getRootDir(), "custom1/log"); - project.setAssignedLabel(slave3.getSelfLabel()); + project.setAssignedLabel(agent3.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setCustomWorkspace(customWorkspaceSlave1.getParentFile().getAbsolutePath()); + project.setCustomWorkspace(customWorkspaceAgent1.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); project.setCustomWorkspace(null); - project.setAssignedLabel(slave2.getSelfLabel()); + project.setAssignedLabel(agent2.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setCustomWorkspace(customWorkspaceSlave2.getParentFile().getAbsolutePath()); + project.setCustomWorkspace(customWorkspaceAgent2.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); - Long customWorkspaceSlaveSize = customWorkspaceSlave1.length() + customWorkspaceSlave2.length() + customWorkspaceSlave1.getParentFile().length() + customWorkspaceSlave2.getParentFile().length(); - assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); - // take one slave offline - slave1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); - assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); + Long customWorkspaceAgentSize = customWorkspaceAgent1.length() + customWorkspaceAgent2.length() + customWorkspaceAgent1.getParentFile().length() + customWorkspaceAgent2.getParentFile().length(); + assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + // take one agent offline + agent1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); + assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); } @Test - public void testGetAllNonSlaveOrCustomWorkspaceSizeWithMaster() throws Exception { + public void testGetAllNonAgentOrCustomWorkspaceSizeWithMaster() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); } else { project.getBuildersList().add(new Shell("echo hello > log")); } - Slave slave1 = j.createOnlineSlave(); - File workspaceSlave2 = new File(slave1.getRemoteFS(), project.getName() + "/log"); - File customWorkspaceSlave1 = new File(j.jenkins.getRootDir(), "custom2/log"); - File customWorkspaceSlave2 = new File(j.jenkins.getRootDir(), "custom1/log"); + Slave agent1 = j.createOnlineSlave(); + File workspaceAgent2 = new File(agent1.getRemoteFS(), project.getName() + "/log"); + File customWorkspaceAgent1 = new File(j.jenkins.getRootDir(), "custom2/log"); + File customWorkspaceAgent2 = new File(j.jenkins.getRootDir(), "custom1/log"); j.jenkins.setNumExecutors(1); project.setAssignedLabel(j.jenkins.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setCustomWorkspace(customWorkspaceSlave1.getParentFile().getAbsolutePath()); + project.setCustomWorkspace(customWorkspaceAgent1.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); project.setCustomWorkspace(null); - project.setAssignedLabel(slave1.getSelfLabel()); + project.setAssignedLabel(agent1.getSelfLabel()); j.buildAndAssertSuccess(project); - project.setCustomWorkspace(customWorkspaceSlave2.getParentFile().getAbsolutePath()); + project.setCustomWorkspace(customWorkspaceAgent2.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); - Long customWorkspaceSlaveSize = customWorkspaceSlave1.length() + customWorkspaceSlave2.length() + customWorkspaceSlave1.getParentFile().length() + customWorkspaceSlave2.getParentFile().length(); - assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); - // take one slave offline + Long customWorkspaceAgentSize = customWorkspaceAgent1.length() + customWorkspaceAgent2.length() + customWorkspaceAgent1.getParentFile().length() + customWorkspaceAgent2.getParentFile().length(); + assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + // take one agent offline j.jenkins.setNumExecutors(0); - assertEquals("", customWorkspaceSlaveSize, project.getProperty(DiskUsageProperty.class).getAllNonSlaveOrCustomWorkspaceSize(), 0); + assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); } @Test @@ -275,7 +280,7 @@ public void testBackwadrCompatibility2() throws IOException { property.getDiskUsage().loadAllBuilds(); assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); assertEquals("Size of workspaces should be loaded from previous configuration.", 4096L, property.getAllWorkspaceSize(), 0); - assertTrue("Path of workspace shoudl be loaded form previous configuration.", property.getSlaveWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + assertTrue("Path of workspace shoudl be loaded form previous configuration.", property.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); } @Test @@ -352,8 +357,8 @@ public void testCheckWorkspacesWithLoadingBuilds() throws IOException { DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); DiskUsageProperty property2 = (DiskUsageProperty) project2.getProperty(DiskUsageProperty.class); property2.getDiskUsage().loadAllBuilds(); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace", property.getSlaveWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace")); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/workspace", property2.getSlaveWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + assertTrue("Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace", property.getAgentWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace")); + assertTrue("Project should contains workspace with path {JENKINS_HOME}/workspace", property2.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); assertEquals("Builds should be loaded.", 2, project2._getRuns().getLoadedBuilds().size(), 0); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index fb1956b8..d797f4b7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -51,15 +51,15 @@ protected static Long getSize(List files) { return lenght; } - protected static Slave createSlave(String name, String remoteFS, Jenkins jenkins, ComputerLauncher launcher) throws Exception { - DumbSlave slave = new DumbSlave(name, "dummy", - remoteFS, "2", Mode.NORMAL, "", launcher, - RetentionStrategy.NOOP, Collections.>emptyList()); - jenkins.addNode(slave); - while(slave.toComputer() == null || !slave.toComputer().isOnline()) { + protected static Slave createAgent(String name, String remoteFS, Jenkins jenkins, ComputerLauncher launcher) throws Exception { + DumbSlave agent = new DumbSlave(name, "dummy", + remoteFS, "2", Mode.NORMAL, "", launcher, + RetentionStrategy.NOOP, Collections.>emptyList()); + jenkins.addNode(agent); + while(agent.toComputer() == null || !agent.toComputer().isOnline()) { Thread.sleep(100); } - return slave; + return agent; } protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build) { diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 34c21bda..38d723a4 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -108,26 +108,26 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project1 = j.createFreeStyleProject("project1"); FreeStyleProject project2 = j.createFreeStyleProject("project2"); - project1.setAssignedNode(slave1); - project2.setAssignedNode(slave1); + project1.setAssignedNode(agent1); + project2.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); j.buildAndAssertSuccess(project2); - project1.setAssignedNode(slave2); - project2.setAssignedNode(slave2); + project1.setAssignedNode(agent2); + project2.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); j.buildAndAssertSuccess(project2); - File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File file2 = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file2)) + slave2.getWorkspaceFor(project1).length(); + File file = new File(agent1.getWorkspaceFor(project1).getRemote(), "fileList"); + File file2 = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); + Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project1).length(); + size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file2)) + agent2.getWorkspaceFor(project1).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); - size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project2).length() + slave2.getWorkspaceFor(project2).length(); + file = new File(agent1.getWorkspaceFor(project2).getRemote(), "fileList"); + size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project2).length() + agent2.getWorkspaceFor(project2).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project2); Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } @@ -139,28 +139,31 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); j.jenkins.setNumExecutors(0); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); - project1.setAssignedNode(slave1); + project1.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); - ArrayList slaves = new ArrayList<>(); - slaves.add("slave2"); - LabelAxis axis2 = new LabelAxis("label", slaves); + Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + ArrayList agents = new ArrayList<>(); + agents.add("agent2"); + LabelAxis axis2 = new LabelAxis("label", agents); axes.add(axis2); project1.setAxes(axes); - File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); - File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); - File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); - Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); - Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); - Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); + File file = new File(agent1.getWorkspaceFor(project1).getRemote(), "fileList"); + File fileAxis1 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + File fileAxis2 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + File fileAxis3 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); + Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project1).length(); + Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); for(MatrixConfiguration c: project1.getItems()) { DiskUsageUtil.calculateWorkspaceDiskUsage(c); } @@ -172,7 +175,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - // next build - configuration are builded on next slave + // next build - configuration are builded on next agent // test if not active configuration are find and right counted // test if works with more complex configurations j.buildAndAssertSuccess(project1); @@ -184,23 +187,26 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2", "fileList"); - fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2", "fileList"); - fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2", "fileList"); - sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); - sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); - sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=slave2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + fileAxis1 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/agent2", "fileList"); + fileAxis2 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2", "fileList"); + fileAxis3 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2", "fileList"); + sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/agent2").length(); + sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2").length(); + sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2").length(); + Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - // matrix project is builded on the next slave - // test if new folder on slave2 is counted too - project1.setAssignedNode(slave2); + // matrix project is builded on the next agent + // test if new folder on agent2 is counted too + project1.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); - file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave2.getWorkspaceFor(project1).length(); + file = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); + size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent2.getWorkspaceFor(project1).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); } @@ -212,30 +218,33 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); - plugin.getConfiguration().setCheckWorkspaceOnSlave(true); + plugin.getConfiguration().setCheckWorkspaceOnAgent(true); j.jenkins.setNumExecutors(0); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); - project1.setAssignedNode(slave1); + project1.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); - File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - File fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2", "fileList"); - File fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2", "fileList"); - File fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2", "fileList"); - Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/slave2").length(); - Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/slave2").length(); - Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/slave2").length(); - file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + slave2.getWorkspaceFor(project1).length() + sizeAxis1 + sizeAxis2 + sizeAxis3; + Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + File file = new File(agent1.getWorkspaceFor(project1).getRemote(), "fileList"); + Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project1).length(); + File fileAxis1 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/agent2", "fileList"); + File fileAxis2 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2", "fileList"); + File fileAxis3 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2", "fileList"); + Long sizeAxis1 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis1)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/agent2").length(); + Long sizeAxis2 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis2)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2").length(); + Long sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2").length(); + file = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); + size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent2.getWorkspaceFor(project1).length() + sizeAxis1 + sizeAxis2 + sizeAxis3; DiskUsageUtil.calculateWorkspaceDiskUsage(project1); Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - plugin.getConfiguration().setCheckWorkspaceOnSlave(false); + plugin.getConfiguration().setCheckWorkspaceOnAgent(false); } @@ -243,10 +252,10 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); - Slave slave2 = DiskUsageTestUtil.createSlave("slave2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); + Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); FreeStyleProject project1 = j.createFreeStyleProject("project1"); - project1.setAssignedNode(slave1); + project1.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); DiskUsageProperty prop = project1.getProperty(DiskUsageProperty.class); @@ -254,10 +263,12 @@ public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesN prop = new DiskUsageProperty(); project1.addProperty(prop); } - prop.putSlaveWorkspaceSize(slave2, slave2.getWorkspaceFor((TopLevelItem) project1).getRemote(), 54356l); + prop.putAgentWorkspaceSize(agent2, agent2.getWorkspaceFor((TopLevelItem) project1).getRemote(), 54356l); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - assertFalse("Slave slave2 should be removed from disk usage, because a workspace for project1 does not exist on this slave.", prop.getSlaveWorkspaceUsage().containsKey(slave2.getNodeName())); - assertTrue("Disk usage should contains slave1, there is a workspace for project1.", prop.getSlaveWorkspaceUsage().containsKey(slave1.getNodeName())); + assertFalse("Agent agent2 should be removed from disk usage, because a workspace for project1 does not exist on this agent.", prop.getAgentWorkspaceUsage().containsKey( + agent2.getNodeName())); + assertTrue("Disk usage should contains agent1, there is a workspace for project1.", prop.getAgentWorkspaceUsage().containsKey( + agent1.getNodeName())); } @Test diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index 96df59a9..bc5ce3c0 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -40,10 +40,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; -import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; @@ -91,15 +89,15 @@ private Long getSize(List files) { return length; } - private Slave createSlave(String name, String remoteFS) throws Exception { - DumbSlave slave = new DumbSlave(name, "dummy", - remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), - RetentionStrategy.NOOP, Collections.>emptyList()); - j.getInstance().addNode(slave); - while(slave.toComputer() == null || !slave.toComputer().isOnline()) { + private Slave createAgent(String name, String remoteFS) throws Exception { + DumbSlave agent = new DumbSlave(name, "dummy", + remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), + RetentionStrategy.NOOP, Collections.>emptyList()); + j.getInstance().addNode(agent); + while(agent.toComputer() == null || !agent.toComputer().isOnline()) { Thread.sleep(100); } - return slave; + return agent; } @Test @@ -108,23 +106,23 @@ public void testExecute() throws IOException, InterruptedException, Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); - Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); + Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave agent2 = createAgent("agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); FreeStyleProject project1 = j.createFreeStyleProject("project1"); FreeStyleProject project2 = j.createFreeStyleProject("project2"); - project1.setAssignedNode(slave1); - project2.setAssignedNode(slave1); + project1.setAssignedNode(agent1); + project2.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); j.buildAndAssertSuccess(project2); - project1.setAssignedNode(slave2); + project1.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); - File f = new File(slave1.getWorkspaceFor(project1).getRemote()); - File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File file2 = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - size += getSize(readFileList(file2)) + slave2.getWorkspaceFor(project1).length(); - file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); - Long size2 = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length() + slave2.getWorkspaceFor(project2).length(); + File f = new File(agent1.getWorkspaceFor(project1).getRemote()); + File file = new File(agent1.getWorkspaceFor(project1).getRemote(), "fileList"); + File file2 = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); + Long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(project1).length(); + size += getSize(readFileList(file2)) + agent2.getWorkspaceFor(project1).length(); + file = new File(agent1.getWorkspaceFor(project2).getRemote(), "fileList"); + Long size2 = getSize(readFileList(file)) + agent1.getWorkspaceFor(project2).length() + agent2.getWorkspaceFor(project2).length(); WorkspaceDiskUsageCalculationThread thread = new WorkspaceDiskUsageCalculationThread(); if(thread.isExecuting()) { waitUntilThreadEnds(thread); @@ -142,24 +140,24 @@ public void testExecuteMatrixProject() throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); j.getInstance().setNumExecutors(0); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); MatrixProject project1 = j.jenkins.createProject(MatrixProject.class, "project1"); project1.setAxes(axes); - project1.setAssignedNode(slave1); + project1.setAssignedNode(agent1); j.buildAndAssertSuccess(project1); MatrixProject project2 = j.jenkins.createProject(MatrixProject.class, "project2"); AxisList axes2 = new AxisList(); TextAxis axis2 = new TextAxis("axis", "axis1 axis2"); axes2.add(axis2); project2.setAxes(axes2); - project2.setAssignedNode(slave1); + project2.setAssignedNode(agent1); j.buildAndAssertSuccess(project2); - Slave slave2 = createSlave("slave2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); - slave1.toComputer().setTemporarilyOffline(true, null); - project1.setAssignedNode(slave2); + Slave agent2 = createAgent("agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); + agent1.toComputer().setTemporarilyOffline(true, null); + project1.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); WorkspaceDiskUsageCalculationThread thread = new WorkspaceDiskUsageCalculationThread(); if(thread.isExecuting()) { @@ -167,36 +165,44 @@ public void testExecuteMatrixProject() throws Exception { } thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); - slave1.toComputer().setTemporarilyOffline(false, null); + agent1.toComputer().setTemporarilyOffline(false, null); // project 1 - File file = new File(slave1.getWorkspaceFor(project1).getRemote(), "fileList"); - File fileAxis1 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); - File fileAxis2 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); - File fileAxis3 = new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); - Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project1).length(); - Long sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); - Long sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); - Long sizeAxis3 = getSize(readFileList(fileAxis3)) + new File(slave1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); - file = new File(slave2.getWorkspaceFor(project1).getRemote(), "fileList"); - fileAxis1 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); - fileAxis2 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); - fileAxis3 = new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); - size += getSize(readFileList(file)) + slave2.getWorkspaceFor(project1).length(); - sizeAxis1 += getSize(readFileList(fileAxis1)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); - sizeAxis2 += getSize(readFileList(fileAxis2)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); - sizeAxis3 += getSize(readFileList(fileAxis3)) + new File(slave2.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); + File file = new File(agent1.getWorkspaceFor(project1).getRemote(), "fileList"); + File fileAxis1 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + File fileAxis2 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + File fileAxis3 = new File(agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); + Long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(project1).length(); + Long sizeAxis1 = getSize(readFileList(fileAxis1)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + Long sizeAxis2 = getSize(readFileList(fileAxis2)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + Long sizeAxis3 = getSize(readFileList(fileAxis3)) + new File( + agent1.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); + file = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); + fileAxis1 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1", "fileList"); + fileAxis2 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2", "fileList"); + fileAxis3 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3", "fileList"); + size += getSize(readFileList(file)) + agent2.getWorkspaceFor(project1).length(); + sizeAxis1 += getSize(readFileList(fileAxis1)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1").length(); + sizeAxis2 += getSize(readFileList(fileAxis2)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); + sizeAxis3 += getSize(readFileList(fileAxis3)) + new File( + agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); // configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); // project 2 - file = new File(slave1.getWorkspaceFor(project2).getRemote(), "fileList"); - fileAxis1 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1", "fileList"); - fileAxis2 = new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2", "fileList"); - size = getSize(readFileList(file)) + slave1.getWorkspaceFor(project2).length(); - sizeAxis1 = getSize(readFileList(fileAxis1)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); - sizeAxis2 = getSize(readFileList(fileAxis2)) + new File(slave1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); + file = new File(agent1.getWorkspaceFor(project2).getRemote(), "fileList"); + fileAxis1 = new File(agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis1", "fileList"); + fileAxis2 = new File(agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis2", "fileList"); + size = getSize(readFileList(file)) + agent1.getWorkspaceFor(project2).length(); + sizeAxis1 = getSize(readFileList(fileAxis1)) + new File( + agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); + sizeAxis2 = getSize(readFileList(fileAxis2)) + new File( + agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); // configurations assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); @@ -223,8 +229,8 @@ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throw FreeStyleProject project = j.getInstance().createProject(FreeStyleProject.class, "project1"); TestDiskUsageProperty prop = new TestDiskUsageProperty(); project.addProperty(prop); - Slave slave1 = createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); - prop.putSlaveWorkspace(slave1, slave1.getWorkspaceFor(project).getRemote()); + Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + prop.putAgentWorkspace(agent1, agent1.getWorkspaceFor(project).getRemote()); Thread t = new Thread(testCalculation.getThreadName()){ @Override @@ -272,9 +278,9 @@ public void testDoNotCalculateExcludedJobs() throws Exception { excludedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); includedJob.getBuildersList().add(new Shell("echo ahoj > log.log")); } - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); - excludedJob.setAssignedLabel(slave1.getSelfLabel()); - includedJob.setAssignedLabel(slave1.getSelfLabel()); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); + excludedJob.setAssignedLabel(agent1.getSelfLabel()); + includedJob.setAssignedLabel(agent1.getSelfLabel()); j.buildAndAssertSuccess(excludedJob); j.buildAndAssertSuccess(includedJob); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); @@ -288,36 +294,36 @@ public void testDoNotCalculateExcludedJobs() throws Exception { @LocalData public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { FreeStyleProject job = j.getInstance().createProject(FreeStyleProject.class, "project1"); - Slave slave1 = DiskUsageTestUtil.createSlave("slave1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); - job.setAssignedLabel(slave1.getSelfLabel()); + Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); + job.setAssignedLabel(agent1.getSelfLabel()); j.buildAndAssertSuccess(job); j.buildAndAssertSuccess(job); j.buildAndAssertSuccess(job); - File file = new File(slave1.getWorkspaceFor(job).getRemote(), "fileList"); - Long size = getSize(readFileList(file)) + slave1.getWorkspaceFor(job).length(); + File file = new File(agent1.getWorkspaceFor(job).getRemote(), "fileList"); + Long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(job).length(); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces()); - assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllSlaveWorkspaces(), 0); + assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces()); + assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces(), 0); } @TestExtension public static class TestDiskUsageProperty extends DiskUsageProperty { @Override - public void putSlaveWorkspaceSize(Node node, String path, Long size) { + public void putAgentWorkspaceSize(Node node, String path, Long size) { LOGGER.fine("workspace size " + size); try { Thread.sleep(10000); // make this operation longer } catch (InterruptedException ex) { Logger.getLogger(WorkspaceDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } - Map workspacesInfo = getSlaveWorkspaceUsage().get(node.getNodeName()); + Map workspacesInfo = getAgentWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); } workspacesInfo.put(path, size); - getSlaveWorkspaceUsage().put(node.getNodeName(), workspacesInfo); + getAgentWorkspaceUsage().put(node.getNodeName(), workspacesInfo); saveDiskUsage(); } } diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory.zip index 10792236f60ad4d226cdb41a56ba31ff9c620ad9..052828894cb4970f82c1e6b4ccd300f7565ab188 100644 GIT binary patch delta 2222 zcmZvcZA@EL7{~3|fMv4VYjA}uqZB136xy`~Vgg|_IyKsEw3gMa1ZZWvjR9>kql<2? zqVZ)}#_~7l2kS7y4`QYTMBEFm*aUO|#KbR}P0;BFlO>QW@w4}wdr$A7-KX~ao|k)` z-+kKU#J1(cwq&aZ7hb5sTHrJG`D^<*Y&Pa&w6YZETXs*U`l1E+Bv690EmcVRc5ILI zbPZy|X+t!>5MFPM3X(1>)(@C)C(N?)Y1T;>%8e%6_C1T!!3J8K$1utt-#tBZ&|}b! zdCjMA-Sf0|Dh=;Jsdpceovf2aBTa5>c8MguP=v9fS`2lI)On@^4r2j(=#roJ^vfj* zd7s}ZUSEt*AcPaWTQ2LgJcoNKQiqaFYl z%(T`cab?;DS}#oe)M0gEo$`rwB2KJRHgWJEmi%H*IC@9Z`XYq9j_Q3_lVsdETEk2Iw&LuEX`_XYm4No3%QM!IvpfRSEoR!%5seK8PyR`%s0egF!`K=0@@Qn6fmP zqpD2X4Z19w?gRKVV4{!bZggF2SdOVOt$9XOXxb6GydN81N%-^YD!hCC35>jMCgUDV z&N?wLTT4S^mlw{|0Ev2Wao&l)u2f(JX7Za?NwOf-SBU=fW4Qa1nM@pF=#39|!EvjR zywl8%;p&~RCR}LyNFx8JC{=Al)3^&O3VPM2_Ngv}`9>W&Zb>B1&(OMUC)}fM(xo2V z_DA5Db0P7CM3y)*V#Qa0kxOd($ctLx4)}%&usXaK(TNIjU&PyS>9smEeJqi9fMu^n zWu$(rMgNx)`IjTb)vycU&n3e!lCxIfuVntR1?w>r3V)Cc_p@S_Ne?-GSm|0R6vVFj zh%uN2+tLoSPMOKcm$CwrQ+6~Z&7|%~R$y`d8Ei~RyJl^6)XrAK-`LSnF+la+69LtGu~#TrB1elS3jbJf-kQvM*d->^uo+U_B-LR9+) Ti)5*NJ1X4LK3<8dE06vUbCGuW delta 2265 zcmZ{kTWnKx9LLi?Sf-J)(@aZ;+I2`4Mwx4i@_=ls8^K+mvy)xi-0Xo}Iy>0_;{_G0 zmxn#b2H#~8wc7|$v#8Ln7%p*JVR4XvpTMylsI zUTxN@Jt)kz!rr}D- zP^}Zyg(?EKjG4M#4(H_l``OU$oC{MlE=HP;MHOgAPUYA>jf#<0_~fJUn;mrorXUbT zpP7T<6R9#$U%@}vs46YDVY!n&cPr)jOV+6qv~Nu}$bw7jCY2+)PEZTF2dM=IDRkBo zIYhm&3Q^chXJ~B35iWP85vHQ6ajj^hj?syw8#$QX?SQMssv@Oz#IvSmkQJdC^_)>o z8fFbG$w}Vc=7sAqE4~R*5=Z%0FoUxC)v$*0{r(J}G)KxWEkC546=SGtpoO0kwIU0g zwz;nGQ)v_s!1OX^q)%pMUU++3=0qAr9Omt9P3m#XB&IRaRL(Hvt;J~Z6H|LWUK4j6 zJX4OqmlBfa#FKsHj01NLn(^HyGLBr5OfmSQn}sW53FTor;X(b3#5}v<|FKxSqsrtC z+`S;N$@?PVaW?`N?aa4_YV>cPn04VdH4yhvfD9QMEW^Eo#9ptbh+g7-uN;GyCHDKu zKvK!WzcJjl~tb~h8zM_8=+So+X|duJu~*^6qK6H>I2E%Qe=dSZ5!td%oo-FvyDm#sj~ zZizvWcXK1JqBV&1VwOsr4>t)DCT4x?mu5jIN<4+(cVrFk=@zkTL8OdhV)-u#>GFID z5)mus#OAaBEfJ1aYE61ug>>>KDT;zOEYK!olQC=IpWbZTdGh5#wyfJ?YDaR$LtE&M zn11Erf0!}Ufu9zfm_M;m{c1b=lfPyg()J3M{>P9TV$d)o*A(DIv;_Gvm!*;)K}8tg zxb9;M`vl>u>xLhr`^B#0htw&gi+)_x0<;AA(a|NOlOMN4QS_s+TgWCq7?f)Slg#*5 z(CC6R1jT*na{R2RSzbJ@o*}dPC$JhrvGweuUi>lTz;Lx0i^XP~o!x-HV|LaU(&TqX z)?(LG8FTfiubYq>sbs_av7c>tP5s$|7Q;*`X;3}{j3-iL7PR3#gsSBrY7ZMd}f$iH}$ Bk>3CS diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists.zip index 10792236f60ad4d226cdb41a56ba31ff9c620ad9..052828894cb4970f82c1e6b4ccd300f7565ab188 100644 GIT binary patch delta 2222 zcmZvcZA@EL7{~3|fMv4VYjA}uqZB136xy`~Vgg|_IyKsEw3gMa1ZZWvjR9>kql<2? zqVZ)}#_~7l2kS7y4`QYTMBEFm*aUO|#KbR}P0;BFlO>QW@w4}wdr$A7-KX~ao|k)` z-+kKU#J1(cwq&aZ7hb5sTHrJG`D^<*Y&Pa&w6YZETXs*U`l1E+Bv690EmcVRc5ILI zbPZy|X+t!>5MFPM3X(1>)(@C)C(N?)Y1T;>%8e%6_C1T!!3J8K$1utt-#tBZ&|}b! zdCjMA-Sf0|Dh=;Jsdpceovf2aBTa5>c8MguP=v9fS`2lI)On@^4r2j(=#roJ^vfj* zd7s}ZUSEt*AcPaWTQ2LgJcoNKQiqaFYl z%(T`cab?;DS}#oe)M0gEo$`rwB2KJRHgWJEmi%H*IC@9Z`XYq9j_Q3_lVsdETEk2Iw&LuEX`_XYm4No3%QM!IvpfRSEoR!%5seK8PyR`%s0egF!`K=0@@Qn6fmP zqpD2X4Z19w?gRKVV4{!bZggF2SdOVOt$9XOXxb6GydN81N%-^YD!hCC35>jMCgUDV z&N?wLTT4S^mlw{|0Ev2Wao&l)u2f(JX7Za?NwOf-SBU=fW4Qa1nM@pF=#39|!EvjR zywl8%;p&~RCR}LyNFx8JC{=Al)3^&O3VPM2_Ngv}`9>W&Zb>B1&(OMUC)}fM(xo2V z_DA5Db0P7CM3y)*V#Qa0kxOd($ctLx4)}%&usXaK(TNIjU&PyS>9smEeJqi9fMu^n zWu$(rMgNx)`IjTb)vycU&n3e!lCxIfuVntR1?w>r3V)Cc_p@S_Ne?-GSm|0R6vVFj zh%uN2+tLoSPMOKcm$CwrQ+6~Z&7|%~R$y`d8Ei~RyJl^6)XrAK-`LSnF+la+69LtGu~#TrB1elS3jbJf-kQvM*d->^uo+U_B-LR9+) Ti)5*NJ1X4LK3<8dE06vUbCGuW delta 2265 zcmZ{kTWnKx9LLi?Sf-J)(@aZ;+I2`4Mwx4i@_=ls8^K+mvy)xi-0Xo}Iy>0_;{_G0 zmxn#b2H#~8wc7|$v#8Ln7%p*JVR4XvpTMylsI zUTxN@Jt)kz!rr}D- zP^}Zyg(?EKjG4M#4(H_l``OU$oC{MlE=HP;MHOgAPUYA>jf#<0_~fJUn;mrorXUbT zpP7T<6R9#$U%@}vs46YDVY!n&cPr)jOV+6qv~Nu}$bw7jCY2+)PEZTF2dM=IDRkBo zIYhm&3Q^chXJ~B35iWP85vHQ6ajj^hj?syw8#$QX?SQMssv@Oz#IvSmkQJdC^_)>o z8fFbG$w}Vc=7sAqE4~R*5=Z%0FoUxC)v$*0{r(J}G)KxWEkC546=SGtpoO0kwIU0g zwz;nGQ)v_s!1OX^q)%pMUU++3=0qAr9Omt9P3m#XB&IRaRL(Hvt;J~Z6H|LWUK4j6 zJX4OqmlBfa#FKsHj01NLn(^HyGLBr5OfmSQn}sW53FTor;X(b3#5}v<|FKxSqsrtC z+`S;N$@?PVaW?`N?aa4_YV>cPn04VdH4yhvfD9QMEW^Eo#9ptbh+g7-uN;GyCHDKu zKvK!WzcJjl~tb~h8zM_8=+So+X|duJu~*^6qK6H>I2E%Qe=dSZ5!td%oo-FvyDm#sj~ zZizvWcXK1JqBV&1VwOsr4>t)DCT4x?mu5jIN<4+(cVrFk=@zkTL8OdhV)-u#>GFID z5)mus#OAaBEfJ1aYE61ug>>>KDT;zOEYK!olQC=IpWbZTdGh5#wyfJ?YDaR$LtE&M zn11Erf0!}Ufu9zfm_M;m{c1b=lfPyg()J3M{>P9TV$d)o*A(DIv;_Gvm!*;)K}8tg zxb9;M`vl>u>xLhr`^B#0htw&gi+)_x0<;AA(a|NOlOMN4QS_s+TgWCq7?f)Slg#*5 z(CC6R1jT*na{R2RSzbJ@o*}dPC$JhrvGweuUi>lTz;Lx0i^XP~o!x-HV|LaU(&TqX z)?(LG8FTfiubYq>sbs_av7c>tP5s$|7Q;*`X;3}{j3-iL7PR3#gsSBrY7ZMd}f$iH}$ Bk>3CS From 526febefba5da9a72e10b8e4686b0e7aadfeb160 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 15:03:01 +0000 Subject: [PATCH 054/158] Adds README.md Imported from [1], which was exported from old Wiki, still visible at [2] [1] https://github.com/jenkins-infra/plugins-wiki-docs/tree/master/disk-usage [2] https://wiki.jenkins.io/display/JENKINS/Disk-Usage-Plugin.html --- README.md | 274 ++++++++++++++++++++++++++++++++++++ docs/images/du-overview.png | Bin 0 -> 28265 bytes docs/images/du-project.png | Bin 0 -> 78415 bytes 3 files changed, 274 insertions(+) create mode 100644 README.md create mode 100644 docs/images/du-overview.png create mode 100644 docs/images/du-project.png diff --git a/README.md b/README.md new file mode 100644 index 00000000..76b49d31 --- /dev/null +++ b/README.md @@ -0,0 +1,274 @@ +This plugin records disk usage. + +# Configuration + +Showing disk usage trend graph is optional - unselect the "Show disk +usage trend graph" checkbox on the global configuration page ("Manage +Jenkins" -\> "System configuration") if you don't want to see the graph +on the project page. + +# Usage + +When you install this plugin, disk usage is calculated each 60 minutes. +You can see project list with occupied disk space by going to the "Disk +Usage" page in the management section (Dashboard -\> "Manage Jenkins" +-\> "Disk Usage"). The same page also allows you to schedule disk usage +calculation immediately. + + +![](docs/images/du-overview.png) + +More detailed information can be seen on the project page, where you can +find disk usage for each build and workspace, as well as a graph with +disk usage trend. + + +![](docs/images/du-project.png) + +# Change Log + +### Upcoming changes + +### Release 0.29 (Coming soon) + +- Add support of Disk usage stats for ItemGroups like Folders + ([commit/6bb9c07a051daba18d6975212416eca48ed48743](https://github.com/jenkinsci/disk-usage-plugin/commit/6bb9c07a051daba18d6975212416eca48ed48743)) +- Add disk usage checks of unloaded jobs and builds + ([commit/1c34d56d1508f6c29f8881b7bdc51c194fc96cab](https://github.com/jenkinsci/disk-usage-plugin/commit/1c34d56d1508f6c29f8881b7bdc51c194fc96cab)) +- Remove thread sleep during check rescheduling after changing CronTab + settings blocks "configSubmit" + ([JENKINS-30934](https://issues.jenkins-ci.org/browse/JENKINS-30934)) +- Fixed alignment of project graph + ([JENKINS-30586](https://issues.jenkins-ci.org/browse/JENKINS-30586)) +- Fix image URLs ([PR + \#34](https://github.com/jenkinsci/disk-usage-plugin/pull/34)) + +### Release 0.28 (Oct 01, 2015) + +- Remove excessive logging (JENKINS-30718) + +### Release 0.27 (September 21 2015) + +- Require admin permission to calculate disk space (JENKINS-23100) +- Add disk usage as post-build step  + +### Release 0.26 (September 14 2015) + +- Fix bug where saving configuration resulted in multiple Job Config + History entries (JENKINS-22224) +-   + +### Release 0.25 (January 26, 2015) + +- Plugin doesn't rely on the format of `Run.id` any more ([pull + \#26](https://github.com/jenkinsci/disk-usage-plugin/pull/26)) + +### Release 0.24 (August 5, 2014) + +Partially based on Git commit messages, it is difficult to pair them +with Jira tasks. + +- Update disk usage changelog + ([JENKINS-20604](https://issues.jenkins-ci.org/browse/JENKINS-20604)) +- Add workspace information in plugin main page +- Separate not current slave wokrspace +- Add current state into overall graph +- Separate scale for workspaces +- Enable excluded jobs for disk usage calculation +- Fix size style on job page +- Fix typo + move methods getValue and getUnit into + ProjectDiskUsageActionFactory class + +### Release 0.23 (November 12, 2013) + +Based on Git commit messages, it is difficult to pair them with Jira +tasks. + +- Add test + fix bug which they catch and better line for graphAdd + test + fix bug which they catch and better line for graph +- Reverse build order in graph +- Make graph huger +- Make free space in job directory optional in global graph +- Better sheduling automatic calculation +- Move information about project disk usage form config.xml of job +- Fixing typo direcotory -\> directory +- Display next execution time and add buttom for builds, jobs and + workspaces +- Fix link in menu on main page + +### Release 0.22 (October 18, 2013) + +Based on Git commit messages, it is difficult to pair them with Jira +tasks. + +- Fix tests - HudsonTestCase perform tests in the same jenkins home + directory, so test have to do clean up +- Fix test +- Display all workspaces +- Save history +- Fix backward compatibility, fix concurent modification exception and + make timeout workspace configurable +- Replace Util.isSymlink +- Fix backward compatibility +- Control if diskUsageWithoutBuild!=null +- Check if slaveWorkspacesUsage is not null +- Change developer +- Better colors for graph +- Add backward compatibility +- Add tests and fix bug which test find out +- Correct information about author +- Add tests for case the slave is deleted or workspace of project was + deleted +- Fix problems with claculation threads and removing workspaces form + diskUsage set if do not exist or its slave does not exists +- Add tests +- Fix problems with symlinks +- Add filter for builds age +- Fix issue with graph +- Add e-mail warnings +- Configurable disk usage calculation +- Another type of graph +- Rewrite creation of graphs +- Add funkcionality for counting disku usage of workspaces + tests +- Change behaviour for counting jobs size and builds size + add tests + for it +- Rewriting disk-usage classes structure + +### Release 0.21 (September 9, 2013) + +- Added option for workspace calculation timeout configuration ([pull + \#14](https://github.com/jenkinsci/disk-usage-plugin/pull/14)) +- Added French translation ([pull + \#13](https://github.com/jenkinsci/disk-usage-plugin/pull/13)) +- Don't follow symlinks ([pull + \#12](https://github.com/jenkinsci/disk-usage-plugin/pull/12)) + +### Release 0.20 (June 5, 2013) + +- If workspace doesn't exists, use zero size instead of using previous + workspace ([pull + \#11](https://github.com/jenkinsci/disk-usage-plugin/pull/11)) +- Traditional Chinese translations ([pull + \#10](https://github.com/jenkinsci/disk-usage-plugin/pull/10)) + +### Release 0.19 (March 15, 2013) + +- Fixed link Jenkins management section + ([JENKINS-16420](https://issues.jenkins-ci.org/browse/JENKINS-16420)) +- Fixed root link to preserve protocol + ([JENKINS-15565](https://issues.jenkins-ci.org/browse/JENKINS-15565)) +- Fixed Compute maven module disk usage + ([JENKINS-15534](https://issues.jenkins-ci.org/browse/JENKINS-15534)) +- Setup workspace timeout and added calculation of the build + immediately after the build ([pull + \#9](https://github.com/jenkinsci/disk-usage-plugin/pull/9)) + +### Release 0.18 (September 4, 2012) + +- Fixed DiskUsage dont show values + ([JENKINS-14248](https://issues.jenkins-ci.org/browse/JENKINS-14248)) +- Overall disk usage graph, removed some deprecated methods ([pull + \#8](https://github.com/jenkinsci/disk-usage-plugin/pull/8))  + +### Release 0.17 (May 24, 2012) + +- Added support for hierachical job model ([pull + \#6](https://github.com/jenkinsci/disk-usage-plugin/pull/6)) +- Fixed broken showGraph ([pull + \#7](https://github.com/jenkinsci/disk-usage-plugin/pull/7))  + +### Release 0.16 (April 13, 2012) + +- Fixed wrong URL in LHS menu + ([JENKINS-12917](https://issues.jenkins-ci.org/browse/JENKINS-12917)) +- Fixed possible NPE during Jenkins startup + ([JENKINS-12970](https://issues.jenkins-ci.org/browse/JENKINS-12970)) + +### Release 0.15 (February 26, 2012) + +- Migration from job property to project action which fixed couple of + things + ([JENKINS-12870](https://issues.jenkins-ci.org/browse/JENKINS-12870)) +- Link to disk usage plugin added to main page as /manage is + restricted only for users with admin rights + +### Release 0.14 (June 27, 2011) + +- Fixed NPE + ([JENKINS-8844](https://issues.jenkins-ci.org/browse/JENKINS-8844)) + +### Release 0.13 (March 26, 2011) + +- Japanese translation  + +### Release 0.12 (Oct 22, 2010) + +- Bug fix - workspace disk usage shows wrong values in some cases + ([JENKINS-7867](https://issues.jenkins-ci.org/browse/JENKINS-7867)) + +### Release 0.11 (Jun 4, 2010) + +- Sort functionality + ([JENKINS-3531](https://issues.jenkins-ci.org/browse/JENKINS-3531)) +- Update Build only if disk usage changed + ([JENKINS-5731](https://issues.jenkins-ci.org/browse/JENKINS-5731)) +- Check also workspace for changes +- Calculation interval changed to 6 hours +- Values of sums moved to bottom of table + ([JENKINS-5749](https://issues.jenkins-ci.org/browse/JENKINS-5749)) +- Some typos + ([JENKINS-4691](https://issues.jenkins-ci.org/browse/JENKINS-4691),[JENKINS-5748](https://issues.jenkins-ci.org/browse/JENKINS-5748)) + +### Release 0.10 (Feb 10, 2010) + +- Update code for more recent Hudson + +### Release 0.9 (May 28, 2009) + +- Fixed a problem where prolonged disk usage computation can starve + other timer activities, like polling. + +### Release 0.8: + +- Now works with Hudson ver. 1.293 (for details see + [JENKINS-3340](https://issues.jenkins-ci.org/browse/JENKINS-3340)) + +### Release 0.7: + +- ? + +### Release 0.6: + +- Added sum of values on the top of the overview page. +- Disk usage for build is recalculated each time to reflect artifacts + deletion. +- Default trigger interval prolonged to 60 minutes. + +### Release 0.5: + +- Fixed "Back to Dashboard" link. +- Added option for showing trend graph. +- Fixed and reversed ordering on the overview page (the most space + consuming projects are on the top of the page now). + +### Release 0.4: + +- Fixed NPE. + +### Release 0.3: + +- Icon changed. + +### Release 0.2: + +- First available public release. + +# Missing features and known bugs + +- The trigger interval should be configurable + [JENKINS-13246](https://issues.jenkins-ci.org/browse/JENKINS-13246), + [JENKINS-10116](https://issues.jenkins-ci.org/browse/JENKINS-10116) +- The disk-usage of the whole job should be shown too, because it's a + very important value. +- [All open + issues](https://issues.jenkins-ci.org/secure/IssueNavigator.jspa?reset=true&jqlQuery=project+%3D+JENKINS+AND+component+%3D+disk-usage+AND+resolution+%3D+Unresolved+ORDER+BY+priority+DESC%2C+key+DESC&mode=hide) diff --git a/docs/images/du-overview.png b/docs/images/du-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf6c49ee94c373a59b13ad6eca15887bc7bbe42 GIT binary patch literal 28265 zcmbUHbzEFa&^C%L+}%Bp;O-DK1PSi0!3jFJTL=V);O-FI-Q7KSV1m1Qurutv-}gKB z+&}L5-SJgx&Fb#zs;8@;s!$~bDKunaWB>rrq(6zP000aN06-ZbLPI1oq%FgcFDNG! zDKVg8f^;8p0BG7=8ZeIFff_1l)2{hNzDF(Sjg1JQ|Le$WhE=!R2XJdMqQ^dkIOD%#zsO0f-)iM*cG#y&Pu-%?Q^t= zj`txBSNoCIQW zvFCoWvJBdB-6@rCy_B6mEv?Js(q$Vkpn}&(8NNKzkcF+k}i`)=863-_$HnV zTHG!=`9XYh$iKKWeoou}9#JW`WoOr}VZng;m$DR@3*_VJekM{QB9~5=GeCTcfv@}a zI~gKvSeSBGiXf3;#OByBirJ1;#2^RvXo{j0@e>|G`f#{|*n)f{&Is-mHkE~Osd+`b zd}7#Ji};jvuEWYby%A`mK1qy7Wl<-^;gIu@hH|R-KHNmk7DZ!M9TwhO<0NVWDYN$HOiuXf zv3VmT>zwcEY;w4(>*8_I_|x3AN-5=d_8VGBY}(E)NcTv?H{+ufv;Nm%I*s0|3=1>y@FXtRJ`go^P%+ZH17R|yS%pLU zt3-C^Mrlkc#c#7C&n5O>!6z2>X%8MTw{xHvhN?tixr-}}CM)%hgkdSqvv>3JSBcNJ z=gQqiF7xqKlbPer)GBMl^3(>vtc`%rtpPx8#U~*EC zCN8Jjkvvk;By3sm`p}x^15)2eG3H8mI#Z9re63e*upD#vWrvP@((-o&tXf?H{@BAB z+s`&GlZ$~vW`PO3HSKDnf-WhmSu{P;p*UOE*){_Nw&vq_v~7RJ#O%zwdBWSpofn}0 z?Eq_o-K?Bmv*WiytHdAsgmf$&np#>~jduE)nwoXm6DA|}_WaK}kt`ytopt%*rSpKl zUa?Yhle?$K5N_B=M@K`h@dj$Co_3(u#2OOdK>A(2Kw=Fcn?8&YMP9k^-Gw<8pQ?bd zpGmu8`1c(Ievq(MDbwS|&*VtD_@6$|JdcT(iJN7ps@gEQ0oca+@k1e?269xhc@NB0 zTZVUS{x!6)-^)p;ePjHG8kc|m3vGW<3U!@sj+UqfwoS!+t2!H1SmZ}pF5F_9-ciHB z!FhOi&riO@Sv~NsH#7NsT0DmP>sD6s;ELKmgBQwIA?Mb(^o141K-=tUlcFO1| z$bg`pX}hk5wZ@9b;>x!|=?|eS?Dc;Z>zxHwIp60j!Utp+AQzKwtylawAmVwe==1d9 zWc4Z+$%o`Bqd6`)jk!7g0_IJea5pD&;->~G6Kd~Z}^=AE>#>spV!M1nRSJkEiUhOvnEry5BY11 z`*78;f7F9peRd0opTXYT2X_SzoyQ$qPD=*BPl9c5f!TP5tfahd(`8Ra-_K=k#Nx6; z#v0>5cCPKTH@ScCd41j?9rWuJ`pdci%@qB7hGLYMv^R? z!TGOR#PN`Snj%h)nx?dOE?@m96TT5gYX4sM7ZM@3v7=Q69`GYq`0e>fEw`0--)wtMfsMP_vTXkCrAKMl#gCtGZ&h_3&sM2F znY#C~cGFvQ;`rQ+&|dTmjtUxMddc=5Y3WF`?ic^Y2guZEjK1G&b7?>{zKjAu)yDO{ zbD1l~j03tN(6IiNS7YG8)9`XaL;azByp=b5?NDe)ltA`8amSi_Kqu(JTWms6z}}nf zXRL>WNp0`umvdoMK;yK%e6E(X>%?g|1@3^TasX3ouO|JAUQv=5&6RBzK}SqX`?(Pn z_?r9NjS6NpFVFk8S`7w5XZ{bvRkw3WV3={f;E6GoO@_&xW zx#6?(S=z8rYv)7l+KOzB8pM;g%Lz~I>83|K&)++<>7tpN&W_nBWYFfwg;&s_i(03z zax%VYo8t1E=Ww@7kEQM)4?Ficz)|&F_?o188CEYAboOhUsnk4@dW8oOyN^v|q18&_ zaqLfjU-}b)ssJxKWnlpb%Amx}a~=noqA8xi;Dg(l;}_@n^ZqB-NzbIyT{8kp;FE9Y z#Kx4gb^&hAU7p|&9scPTomu<2inPK%@A^}~siH?~q+J24A@ZRAtZA{OpSMaf4=N_X z5|smqIzg#G=c~?S6C*Y729EjT>`g~(Eepk>=bo6PZ}r%?NTKay6U{o%wKvoF(r~@} zl_|x-VKB+i7CRT)oCHerw`g+VYn5=KS-p)Nii&U{FMd}K=Inr-Vu4F5R~1xlZ*UJ)N72miXjeMW5x?@|ik<_=_4H&JgY;7oPjY z`iS@=Y~bQ_KYt?fV-PLcl`RovLj1MzkijU)Z2lPbIg{y&23G0KZz}X8C}{rxZjyKQ zZv5=24pg4PKaB*K{T?xEiR5Y#^Z$>xzSjz-7nLT#=9CGni;z+9Y97(U!w&w8RJyR= z^yiO}*M!M3B_i#uYe6njcjZ@UF=lwEOBl2>h zX3@t`x{cA(AsxOtYK z%c?~4aIv_sVA^jPCb~584ii5f3-Ge4`aa#`kQ>HxYRc4Vjcr2<;LNx!xnuL2McBm- zaF6wr)ALgoN~=#8NUUK94bfE)8FTHhAn$iA{tT#A)`mN%ZLGc3cjt3H@%>z`l}A_m z5jXz8DvX2Kzc#{`yX53!l1rCsS6nSIZ))ydO|y{#*Pp(40+{ch9D|hTow1WWT#@bB z8vOqPh)lbH&Q8Bu(P4Wj3Qw+|g+FE=6`!peRnyc|X=uT=i&Z&7yI2c+RK9~Eq1^$o z^?55-zO#E3DzY-qS{`HGI)#63szq+oWhR-8`7jYwf(P2SWJpFy$JL^JN*l%mM>wj~ z<%yt9f8M~4Crv)X7P#lMwWzIDN&YEVu~MODj+5SYEY_omEXKK5vo7b4dN@D5l=+sP z`{|1-X!X;}4;AjLHyhQJmF|H*YP5nB%L3W^CXg^=``_|R;xK7u=%z6n`z1#ZEG>Mb zoDZKvWpC!Hx@UWNXA1K5B_AOl?`h#iTlJvv=nW7ThP4DC2Cw%Kv2%G2 zw86pU+-d8#E}8M`9`1?@QEHeNKcOl)Bxh5+ZiL9LUjpqUkC*GC$%WpxsoqW0(qmYL z1}1)SIdDaT)-(ORYQ0pdQBKTm93)OvU9tFc;rp^jF|R%CZ@!C%98P&K*)lPpg+AbW zq3!=`Oy#LzUv$jc1dMo@^WmvK=@L%=?DLH$J>w`@Pgf44_P=0R-na`j86pW~ndS%}XUxf5edIdfyIn|KR2CKjZ5L5(;*$QZxN_eW zU>{W*hi@3Km{4nB4T*B`J?s-VEk~%J%IZTlfuZaC$CnjH7w1Nu%nHZR0i^vo!8R@1 zyIp6FYTF&Yb#s+)0ZHws+Ln-Cxs$Hug`;If?IAYAwxsI#mzzf-tvLTjCpI=mbETST z-&9XdDmYS@Xr+>pQqq&t4%gQ~mpkKlj2aQ7{4?)Y4=V)}t|EMjmBSm9v3y^2?^#8y zfj!)V8mooob$yeqzv(z$jr9~~_<*IB0!`d(`pH17$dOM*|6fL4iq`G2FRZ*o@qeCC(D9%)^z%%lErpN7ik( zViAedec!LM(5Nd{b(wx@fp*--(8*7};J>Y;q^2109IbfdBVH#(1lM?9hj zzXwJR>-Lb&y37$$G5n}Kp1_yrj|0$xhWmXslKq11zgd6F9sh0{C_coX#@1m-zzlm2 z;+9}YnBsysTRuchs?*$0mGAOfy_!Nf1=U^+i2~;xx*;gn=HiAKm-Yh9l|TV0mItO+ z#&RT)mimT_u{k!K;z)HT&RZyc-=hGXyy+e3ZPKkt=c2>8f#i8}-*2Z-{-7Ao^~{gU zl0o-Gek|_IBX^(X5*|E^8F#h|hZvMld@k9uI@-KhlXB_20z?tmB`(_=^egU7`n%^p zmL1KB{kxTvm}8#acLv@h$e^I0Ky}T|a`N!-2n!1{FqAYk-A(0u{1}Xil~g%jH`-LF z&(xWa-yswn(J<6SzF4*pZ{8l^=Ug%Q0`9SwR+|fM6Ou0bjv`2~BS(sdf{cE*omJbK z7-451ay0N{gCy_K!T=_jfdz&WtTWh#Kl3zS`+KahyZERkF{dun3%C#U+&2<=t#OByItp9F*mW` zXBYLmOG(G>9$VfHlGO;-6!o9$w%aF{#mB_345kADEP2qYj$w6TU*}*}gKX<3s&0*m zC6sUU8_okZZf@Tv_u-z_chKD&ji2QiNP288#vP>9SHFJ-)#iuR_MEc;4uI%9`HR<5Pm3vCf&@ zZTINCIOG z;i0D;rCYzN5SqBoN?Gk0SRf{Oh$#J@MR1yvGmD^Wys>4iqr7VXMLL`vLsi-VDD#8}yV zK+){fJO>NP90e%7Z-%VAbMJ#c2e9t!=IqV>uF?8gDeD_*kY}Mizv$rTYIUj8A$CST zrR%|15Cijb=TxVR$JvV1W?k#lBC(1TQ|v^L$yr_I?nWQ?$B^hk$Wnn$2Ibg7foGL2 z&ZP~(dzhruQgi+aw@W4AK6RlX=2j)$T=u47)2}9_-|kz0uJux)6@?w|?B9K_6;f;!-S2PvICeQ$)A?Rcy9Sv3x zTq#jwfRGGsZf+PD7;ZQW2{HvL65`_S?(W%3H6h(bfd481=NNo?uGmKyiu~=$yJLs( zFTUl(LFh+XMYeft1@U^FY1}8J^3-Kzc3*XHCDiAyBg^-pfjaSxofCyMeb42s#XB~P zb-pM?vrbDr)xlj(&=L`Jm8D*-6g~_zE`)h#`)%5u8vG0G)^_;qICV zX7mXxApcH-vSN62vZf0w$|0x}?`Xauz)vkZtyD#&g#EWP^Lq#SCj-ghmo+OfUG?;) zqp=Op_jM+*=;sF8ayN;$H>uI3}Limr}NG9JK@*KyM<*4 zz6AleC1~_Z)JZ2h8S+DBL{V=CNWX*+@;Etkgdax__ibB@{wO}zW{tR?=7SE}XrT>Tm9CZ!DD2$%Y6d_1G(Qy^a`IH`*-dL@bHTSSX z6>q0v-VkW2ZySK=SKFXOS&|S!f_`9V=)D<;$0fylBT5*Rhlpi?y2ZOece)C9!Z*Wo2Dz1{ScftSy z?z#XFl>9sh3VPApsuo9hCmx>{xXni;Q%z~QikZaj@*M|%FyMSmS$T~c*3Q{C^C{8{~I$TPH{K28d8fg%6GfmU|B5V+W(C;*O(bdd=}&W%yRQ)o?Mer z?9ynlhvqU7q)%HaiB?Nm55(3KQC8zBkrIwa??DLlwm%g6%UNO+UU3g6T9Ab>vXtqEc$BX=8N%$`#?{Lc zS4MOi@s47T&Yvg+h-JsJM7uzwFH8y}TueJf7(3C7f9{;Pu2uQM+$-Dvhas^1o0ISV zl?2;?ltEupI$yC-#9Vebp)Q^?1!=^4m5&iw2}zNNL$Tsb-)sc@AXU;=B^8_gJ6|oD z7Pcky+9K1m+py#plw9&u3I)EzbEZ3y{vyCkT9|J_<1Lc|7h>o~z8oy$BlV>$F%fC) zO8**}1V)yzRLw@ME>>T70Sn)^)E11=@c)7wBqi~9fKAT~g^+S>`}uHbj%Q|DBo}M* zC_gW6v29z_#5^y^8)KsA=z6PiH! zN6EzUmvElWR0&G9+qfdT`(yQ|9as6#rHoDYP%go8c zPj_^1<-r@Q|Kav**b0v&Q_NMRF5x~*M``(-A#C6)5ZPh+nx3$xpHQ}|wR_=v^-~DVg zr1{$|k0U;yzc*3^=`q^Ahz%s_5*GrTbT?iv>0h;D+N3dF}19-XG4r;cX7Lza~mMb^3SGn0fM)B6z3=8rP0h z+TRR#&`0B1*277~8-Vcfkjm3*goZQ2t9B)Acr0flzc*3`?P*1A@6vuM%?WUGZTto{4Zmw(B=97ShXMabfG#CmbnWM-KhNc>C13VKx{0 zc(Nhwkcqq@c1}`ihQ|lAKB7~D8kcnRA&I$Ibii4{qJZVvhBRufl0v&ppm^~Ef(>1C z$u|Cy)yV}~h@yc^^Yvj^=vUG#{RGMW$9(6o#C5)jY6nM48RdUkyety0WV^Y(`hFC(!5kINY9DVD>$#)hd zw2W%IF{pkU8v3YMOl90%b4L$h*z(jA8;W0Tp;5Q|K#R-EgSV?+a+1u#BU!wvSpM_p zXhgTP|4h3GhlA+r-;F4KY>A-FDSc}3ej72I9`I%tyM#F<*L0`g+r$%rPG5zU<&(5s z)Uwr6f$$&rO*3tBPNZKuWncX;|Dc*5Pm*r#;`-_S*xpY%IW2ioAmXvF8L4y!1&=phkD_74dfa@Ihvd=bHY@~;?i|~Snwr&Md|SlRy6o25$*TW2qr3gIT|gtSa8sil z{NwKVuaA4>a4V^Ec3VBZOPt)nv=WWmDZ9sIgrO@xo;BAK!nO}7AEo*BHxU63`juxF zGxOH$c3Fc{_HBEEbnp={u(jLSgRoFx|D|!rIZC3OU#&s%VDG4(6p!CRwmh7_ zJ<0tsNyqc)?K0V2#ljhyehsT)BVS@a25P^U@1Njbee_JZlW_i9TFq^SZ5IB)$)YT5w?EX2hryTRu)-nhEa{Nq zJnkI%6~Bg5L*68Wt%3$DasHXxPwG@rVbUYpQCW7K)7<~~`bD5JI%BW`;w$`N<~w%V zJpAKjZ~mV^`2RwX5DXgv{Cgjnb*FmAgfIOYo0}jb#*C&WK2q4%QF;Uvb1?=NLj8MH z+n@hX8MDs#|FhNqFF_0~{LX(+T&%)3-AVZ0fyWm?JGG<5YroXF1FASW2RcJGjpsUO zfG)L=F3-?HJJE~~m?A-C8hz;p{2>7x&~7kk&x!i>$e1t~TspfCbY=4b{%hF;U!GdN zaHDg-s!5|PkhJOV!ge(&!R#6^Xane$EZ$I=>^p^LZQE=bvam ztuO4!X@|C1FSS6yls}jzzCY{`!9&yfp?PA3<8OG5-&A}pGY$a#CN{|(B9gL0fij}-^F^cY$Jz^UfYua(TtfV#%B8J z+VzU?s$;3v0neA2Qi{5ZKmE2MPuxy}LLNqojZW|lw~5gH?U`B>bdY&ex9_;x2J@0{ zS>ZG)YVNN2cnx$G&7vK9x|G)>edA+DOig8As%Ui3Pf1DfPDHNGoww|h(a=b&540D2 z^+x(eyjJ&H2bFpGjf#0r9l$664hRi022dk3CQG3HXv`18Ly_&+`dSZU8&WJ~TSlpz zpWm7l<3Mzb-c>-Ycgkn7n-2~Fx>AYKoOE3}?`)Y9_E>~$l@FS38|z6$9y18tK>Fvf z+o_6;i4CVd_pM(Bd7ti2iYz8st*k0J?E>VvzKQVd^`5YnZG%u0xo=UJO_aPni}vg`8JeYi@ZG66d9=qI4s&kmaIfQ}g%5BSz9NmQ0 zdk0jx?ufjrI8E^V47sSja>S4VR{{DL)S0(S$iUKn$sT^;e5FQhpS3;VZ-KxhjQrfXUys*pd@K(%brn66z-n&=lS z-Hzvc&Ok?dQokYz!ENLwk33F%3+KZoIK}OvJb?`A&GpqVl1N5-qDGm;sCi$au+r&c zN8yN|Zch`4q@AXn`R4O{*{AsU=`0-HOc?1DV>l;2;+h2;+MpT{u-FcuIk z=W3o8Ln~1d@UJT?a^K{F$||mOKcs_M#aJk-pS)Yp* z0|f=g{7&|_r)dPX_HBOVC(pvvApN*xbr=JhQq%}d6n@j(;_{cvY`tYvgEd+eO3#Hc^m(pZH1Hs%?sI^Cb zLc|BQ_kYx>1^oWD<5X0ON~?;cbIe`P$nLngH538zS_nVi?^Q2g?YVnqeLgQg0 zvslXc`Ut%r_2Z+Ad;y&t&hPy3M7L|7ftLoy{V9AZ-W^6t0u)qMk59m#47UDXwzrx$ zC<4`Htx`XaV+aR{$$vMCSgZ{%uG>Qlda9tPlaTbuF{_IQ&1bozF)7+*>8r@zaJj(m z-iUsio4%a@CPI@EcgMr1q6=&!wAV*{RLD6_JQ@iPZn#WBjd^5h5Q8eNj6}IkeIFV_ zeDrlP)1|Odomz<_==SEi5?{R*bh-FkiE0n-q5v;KlrR)--tTTH(^EOfYC7Yh7N8~r z1xx`z5VVX;x|@-a4x{9>v!(dmg45sgjj%@I$jlC#_l&1AMU0}@tWn9cFTczD@)m44 zl37ojW}$(?|2AM-40KFjY`Z z^U1c9R5cC3GU~e<7 zrRBje?LK4uOZsf;^|fBEHB%qzM00#pOsi;ecdBu}w=6PNIVU|iJD-7eU=URHp@{jH z8QzZBYNylj)JZu?=ii@8T^I|G?~5A3VZm#!Krb!75d9Q-QApb*Zt@?5Gh!{5Jvvq(%yS*p+%IIoD0$E6G! zh>MSZXK+2qDCBhw3t=jvc_rJ9`ve-HL@Shng1>3LbIhJD4S)}$QQ?=6r4NHn+}@H&{eex3 z^AnQPq{7Qa#y+_W@4buBvb6lk7tpa7Pq%duj7AdnQICbCbH3`3=nA zADF(OgcQ%&1@VQ8UBmp(x_TEs;}0i$IKwe%v1q3V9@tE5#=exqa!kU?&SH0<4m#e9 zsNsVs9=WX}!MjPdP;YiGa?hni49H0=SDmVvWkuROCVJE#6!hF^a{c3WEz%Q(4wcODZ+^)D~3HW1v*=y4$5kA=1^D!yHh+b-}vzB`PUGvnHW1?yI zTV`}*wyLf*$?v*l8q{u>BIw~BGv@d+E~+f!W^Ut7bs>z3(36(W zeAXzw?PATt(VVWf2el(_<=HZ;%kk|p!f7<3`qUjfWOeiS9TRvt4W02JZGK};6()3lw3PHGZ%`7Ul`U&6RC{c#|WdBzccwZ0=z?2bQA2bP<;w{#i zWURKwZwhwd_q_xMmvC_U_+0lTNj_y;jHe!R`5ZobJlXOXBv%z!gscyeCu;FlAY0b& zoJ|DO3!XheP+i4@L&FFR^42dYW76_Wfkk+Wp@&>Dn9W*T)Q zMaYh6-mnx&Lc|cxrDNcrqT+kk_nsUca7z0L8%uI$D9>KDZ%lql$8 zEeRafS(_tZsFG1%zr9z`h7m_cm3X}P?78x@HDuxXL}|RA`&8yG)3PtB-dNfen1~sh=KP^Yr5fc7{TcMyaf zP^H@G&91(0>*@tb$iT1lM*9j&L${;Phr;RJm7hz$Y2F|6ytv)(d7<4OABC$v5&I3= zODPICSsAE$k3!b>`0y~+6*ti9tcS&^Lwv4OM0j%9vRv9-{j$(KH}J9^KbyKDSz z$l6oR-n3>f8VMH_Grp&`Vf~#%W1~nyN@*j7`iv;9A!pS6x7F;#+cYKXrs4(5e>#l% z`9dVQ5gp6{!F9Zy>ajTSz?(z3kgRM}Bs9Ed+*5Ui1TRA^ptG>^Fi$X!u@m0lJ>Yar0zz-e$=dU6Byf~+1g7Kc` zI*^0xxh0zt?BVtny~Ufdr^L-3G6HhLi|&{=3EPvQzeomm6pmKbYvZCySs^6BH!A&a zYk|31Z;HIqJD5*}49-4JpE9+isgHpm)k^9&DxcBr?|ffzj+CwN+ad^sbdaPlf6Fvd z!}^k^y{xQ^F^M&NRUI;~BTKcz59sE4ZQ=x5?xlKqmf9Quu$8c5LGY!Z`vVKN^$<7< zcdhL{Ztn)e#1&=b3Evr{m#kER1b*W2HCX?KL(5{=>hW|?&@1rr-lg$7*z3!>>D@)V zOL=Eu9r@K02%sBZTwpi9D<~x?8O|8l7yS;hq8Z$;Cmlip{5$S8Hm{CbSIiVFXL~@g z$VkAREX$HjZF`8fR0XK!PCSQY0+(aJ4yde3N<4>gU280=}{01EtUxFTN%H(I-@B+nC(23ZVg>Kb4e> z9tO`G@{D5WIhcO_(mvd|3hf^lB$C>A*$T3$Zp1k}_-gj+V>!ElONZ9Nh&(({jIb-L z0PfSKk1u>siEHrrQd>U^>K1tZwAI+T8cTZXiRSz8YzSUv64~DVqU+Z-Y_GWT_fOVB z$)+w0gl(DWMv}>YWKFFRHy()W*{a)K^%T}(d&#R<9k@CLvvH^#^%5p-bHOW>QhR2! z%1!4=MxM*-qFtQ}3VVb-bmv8{k`>bNZf>234Bm$C-^895AFxnnxRF1d#Il~8C0AsP z>Eios80*;OWUf2+FCp+S;or0bcbM1%G!-JeO4Am_egf$t09U8;WX)M-GgeJYWzl(ZBB+Zn0X3 zwq3e8&FLLv(eF%1&(tq5!?iP5S9V!;J`r*q$v5w2Kyabg{-anFW%|peTA&;jsHh-c zSp&bEHNudpom)Q-muCo{`qdvz-KSBf*GT3y*ehmSKKlo6m4@Apx30G$Nww2V-ud1Z zmrA^scF!27lz+S^Z4~(Nt>HoGC6XFRd0Yfr=x%TPwj=pHTl%vkp`r-LBP&TVU2(t4 zbA3bPdCBWs(%97(iCOa={@YyHN|j66jnG49g#D|I24VAzzoP~HB&6KRvRygSu7*V1 zt7}iT{3@)1>5zPoGF!wAQMRZb0OaSlkfuZD!4{aU3z#}Cqugjt~=6bXcSqET}Z28d(poBbGRX_E_5RwO|8E))B*CGZthI10-}Wyt6-JQ7IO#V|DeT zyq;Z!LWjNSqp`vN;U!`?l1w$psI=nT{XJ1+QU;MUKXj-kC%iz-UPvm(!% zZmB1Poe2hDnDUx=r$5@X-X!ADW76V7JbSE4iuk%iftNcETMXXT8YF51L^rlwUNmHU zKk&GFUUL5MW|J#oG?OKanmceQ&}P37)KAR4$K$O?uB7H%1{?OSK6!+VU?+9|&*X$t_z{X}adUGtV1P$04 z{fN#QV;JIp+O?PWy!pWxUl7Whqh`&<2H#E$AeS)Cs;3wM+`5*Q=Tknjy~bZzVY;d! z)Zmq&goU+lG0eYEQKaY9eIa#)uy9)*0KtB2`dLrJkl_m`*ArThMfo3jD5+c=7; z>paS`RJB5AKxJ&z7Vb*}o2*x(R#pZhV+GEI52dxyR?SbPg`IB4rSZ#^8Rty6l(mJ1 z&7*g(E&+aZH0J33#f)rNWgDiqZ{OBQ<20UtEL{5sgW$mYUOU~fPTi4Tyrk6QMspX_ z(;sh$sS9A}0e^~ZmgC$bw`?v}{Wy>9lK^An_!44j`p@U#;a7y%uQVAX8~Pn7k=d*5 zDhLS&(M+#X5epeWl(<6!ruLodzs$Y=yV|o^s`2ac0_7?m-0AaneMB3GSwNd;+NVz% z7S!Sga7n^0!f{S1?r+j}ToPoq4+hj*YZP79vzYuv*x&tU%a~pcOoOfLi6(G319?hx zf`Wp^BI%@OD!rTFms7iqC(HtCe|!JH&zE%t1aA<;p|}Y!nsu}7uUng+lN6;-($A35 znr~Fb8c=o}f?l&MkTipFXi{SmXFsmYHdeR@dE^=iQTrPWw#Z@)#^PN&K72 zu|LORsye|5s&LdXWy*#ExTz!*%WWRVtitxf4qXCqYyBWeh!&nlG0}H}F&Q^nTwOsR ztfD&icitTu!n{oCxe53?3@FG2U)uYwOhI48OEhKX$WJ`o?B^xW0Tvb($X@K+>t@~m zmArbPKl$AO2Oxi=VrnCXWTHv3g~VQgvIHtl8{*RcdNo7A@uqAIUnMy zNF}tdzn@fgIlMg z6wJ)b1Y)wXqCW-*s#Z#RRmyqyZ%E->ICuX{e)~YJRM9iBAeOm=!9>o=TG>^Vx@ze2 zqSjD25*5A~&38S58fi1j88`MQ6|WMI zx@fZW!EAOL5ex8bajwXQk*o|j0C%37Bw<%GCGfqwY4ial)N{A;s+3%3 zInVcx1dlv<^3RTPFUy|;d;>lo8A-RL#U5FyAco@Ri(Z!dD9L!$7KC|WMgo@7f=mw$L^D)x`9{cr%;f;2W}ZY5te za@6Z5F@MUJnX50nc43kt@V4$U@{#MT+=q7tyySR4qH(z}mfz1iQ@nk?K-z{L%g|do z?@TRkM!Kfz{?h6VBjC9zKCi?jQvIhZ$61VCxMH)P!0A!@owwX zsPoS;4|>JjV!0-Zy$9{nPRBHipX=j)O4@#~>Oa3Xc<~Z0Yg6xY3RLWY;pg17yljdV z(I%pxh+ev3?l=gtZ4Ot=TgJ!2QNvd;ek$UtsiKf6Fz)I37qS0`E3>!7jUoXK z`4?0s08?yxdmDNC)O^=-7G9Cn5BM|$DZf<_HZVXP+}_*vvTS3UkUp6^I8 zsd;)GTp-ET)XY!|41@fy|?*&OA2X2KS(xf9X1l%XxX9!&8e z`>21U4_b#A{FUveuw#or!N(&q^}I>JVKI>odi;~O!fOxsi{&6je}80^>`&)X`LH9n zuNBY9&Y4z$Vq&6*_&jJh(Ay`}$!d38iRt|OaUA}}Z!TSaa!0rJ?j6x;7RhkUdzA&~(K43s)-{sIfcUJ?D zf`^G;jkjM`8+^8_PT2qcvOdK3TkC{jk?{O`N;OK(N>@qpP2 zYv9VT4Rl)`-U;L1amImurAoUoM+wB_v$s83p#og#&tV_pU;&sAiNwR&Pezx;<+hLU zy5`qp9Y&p-j4WJx>J~Md7^GY4a0@!(Ee?0ZDC}q zG<+Yd0^;_QP!9yMqEhZ2)-LQ2ZWC8dQ1+-Ugj5e4iFhf9Za(b|sY`XWX_v zpY!m!zRBB%`x3S34gwSO4puB?sOQ!Sx3pUo3UvDMI4qCkKh|7VMHLkU*?N(E%zV!v@1%ynO>|)YB08_UNprZAaGWlE55kG%N&Y#oUR>JKVePhcf+pz18kh#X1vk<|ax0(_=J$dcG-Y&a{T zx!uZ6go!dQ@$!BgoM^7pG6bzBNFr_S<7zS=P+eEYCD->)MI8jTB_6i(F=j2f zqF_kO=P0at$U`rgljYJ(cnha3agpIVYW^v9DPQE=?IoWLQt!Yh^|#8S-W&KQzA0Zs z+3t1My_9=kI|r5jPEKxX6ZE2IBX!srBl70_C-i}I!MNw>o~?UCkb-6`7p6|!!6e#` zw_wxD?w>n@GVku(cTq$tmu?tAAT0@-san7U06tUIK*zHE6GLUbpDe&*)U05I;O1{i z_JOlsK3Y2Fi7>qX##WF9?0QNTLxeu=W?CI;mqb7j!ki8SbrBXeyhde^5KHyCu7T) zC~od3*(28^^}p4T_MXIJ;QUTj>!CP5pFJVa6RQ0z@tDAf5zbvUGyAs5^RA3yKz*s6 ze9b#T-sgB956`lwtsb)vS`4wX85hrRsy^#!n3@q)tW4vk4jb0EH$4cf8jzg)BOp8I;$Y zB$bH@@I)rH8&43{INq_vPI^85#_w;u^|_nR`mayONZZX5MI&+tX_C!tK%4)URd6_?>+f$M2wIaal!@YCpGdjpc(Aae#!*Xgk zZ6jJ#eBi}bk|6OMY1ry(aA&<@ghEyc4bk6^Y9ee#O~L=GsjH5Q>I?Q4Ma2MAN*YCJ z#08{7P#Ov8mZiI6Nd*z4mWHL3ZfR+YC6?}5dO@UXVOio`{JqcTJ^o^M=ggTiXXbq8 z&Y5%W9S(u#T?xO8gpnuTjE#+>iS=UIOxkBA%uWW4hU@Kg%je?M2k&tJJ7rp{qZL+R zEwOJ?9=t|6WmSlKE@r02%hlQn`(U%*Ub_a2`2by+Gd4;3dVvR3!~~X+)KJXwnT4co0k%VxH{JY%0xHa2YC{BB9%CvV z;D<(m0dZxUiWi}2>Yj80q6j=GU) zG8N-4oQ=5gc4_~&{ku+BVPDgkO4{2zzfwKD0-H$y`nHX~*-jn#eRH0VoFdY)2E`O<#su%SS2w!MjgY0O(~Ygk^W=jc9;%W{sIaKZp1N*UG06(jPA+$p?0+1q ze0mc|81X$Xnig_TywX9g;wWf65nb)jyv%v4#_5yig4T;n=FD*mJVnHb=HeUwsM+rq zR{LyMRInV}e5kIj-kP4$aG`3~pRNEvP5?ZZ^}BPC_3isQedN-`YMwOU-B47o8ZQB; zIpdse_++pLTT4gx3f~0eT18$HolPaA8bc~Z-Qp?HlL=*f_96z^MAo9Y(IvsHX90Bp zFcy_6;kcs+s7Z=-uD`h@^s*~eHQ?B0u>1oTeQSMe@z*PK1)RN;2U^3Q&=O?7DTbT2 zVHdq;)V2|EU}nAX%NYtEC~VF^VwAUo`lG!O+BEwK3o8Gb{_fM}TSWSmib$wu)uWPc z>E0vt;1Ko8Oib%LXnCj4c8^NJ9{NT$5sTnBfqCa7%8d^RJjG8@k%mE-K>Qo}uR%$h(fW1U=n%fp5uoJemuInV;#N1KIi9GLiHB6pF*4DiD zm&J7!uDcy|HA7_uu+B644|~N4-eOWYMaFuL8b8BUdG2a4#id*7Y|1!`V@{G08Mm+(GFa#yJV5iBxm7KO@gmC8cXod{0KO za#X+g&#;1Pp%|Z;+=+mjs)QWLq$SSsJ(;Awi%anci=!9XoX8F0e3`x5N7u#Ma9OsS z@EcY~h|(LMJ=3s zizK$IIfZj(xn~03pm$(*J~-cQ`w@r<)Lu8yLshwBgCbdeN=!~f(yB=f4c z6&L@nh<-1~0J1yfC*@)&L-a|nV%MkV>wtzK-3pVuCC}~atq1=#)z#WR)`+JhBIWXt zrCbvoCQg&M9PD_x(XXSc{|VqmxelZ(#Z27Z{+0g2SgdDPy#8ORK}glluX#TttNO7D zCgY_$OG$fRN9ccDm+m&N43{3nOav~ROQk)8G`rltOr&H!y7*KJO_X@P##NKCV3GNg z`QG4vE%Yn97j_Hi=`oWPyjd%l{}_CFMko2m-+LeOD-BM~=UkF~3fb{D z_RF0t-eKm#HI7|qmD2k;F((p19#Zz73sk($cu}NGL5+49%q0K(xb1VF*nO%+0rOb~ z7Z3gX@Nh@Tz-e*1Ayyw7;O+L$F5;hlPspEa{8S1St8OMzuVnQ|d(2(r+}WKuSVc8vbz{3vYZca6tPYxy= zK$DiZqQe46U_*2l9xQ0l@2TiXS)Z@pFJEtIR6LJstHc44luJ0 zbhHOIAMrvSnCukiTeF*_BCZ1w@VkvzGc)FIhXd7pUCFQsA_bd@r1C??;)Q4Z?EbQ z&vQb8%Nf!{0;fMUo0hE9x+u{JdSi~9inQ&0t^uuC)vWOz)YZ0*>nFxzA4%tCJL5l+ zBIOhAwHY>Xg$?$~3gCACf&(a3x&k~o%nbZ1K!PT-c&WXX9<}XVd#=MUcCap47v%*t#STFEwAd5qs-_XTE1it+q3HSQ6K{_&YT z0Z>Z&+<#_15y%ekjv3D*cm5dnJnM94_>0j^JrO@iX01CNE{#L!uT7q3OlykWue$3WV=!}YNjBiv$Dg}cv6J4gE?sSJc!FtD~$d5TGdCr3Gs3j}q^3)eWJn(x`|oJDGizsd8; z>XM{*e9p$!V(B!;-&L=3_AMA;i}FessYQ2&T>B(B|4m#SDsFypj&e{0S2>e)#tb0a z{WIgn6x$g3F*)#=;bavM~6b`SF0gkPHK%iuFxdnPIS*q%t|Kk)wP#`-cGxx z%s9Tj6>q(p9$ zfEk-`T|oFy!HwuyGEC0-=&V7YV#gnq@<3IJXXK!v*niP3$>QV0D(`eo=)z`nL;O?r zKlV^Ju^iMH?lvDuZf&fyoYjpl_giL>uP=Rk?y938u_pGzMdTB+iJz~C(J(G;_r2r! z#oTO0hn)IcAYE3kV;u2As>kn%!IBPJ^&&|WX<7Z^C`TA}$GUQAES!8@Cf0e%ZNDjrJ`fPC~sa%S@AK+!@3iJThZtX=No?u^QYF+`F|w zH#a%iypId8TKS7(t#QJ4qzeZ^5a%g4$t_+xZIBjdsx{r}l$q$yzd~Hu1n;amka~EoZPCEZJ02uII%S%Q^(OU8T z=vW`Gt*sx|)FGu7DRthGvKb0yZ(Htt$A@y`&`@|tr*8C3=>)Q*nH({X-@hqH*;5d- z&qe?cjB4FR;n|Y#5c7N+Wn4OMl#P-Gb?y^Y*-!UO0Px6UQLyXAM5Xj>6vb`p9bQGV z)Gs=vttuz0mPp5yw+FHowmlW`F9?86Q40%;P&fm9lx#?IVfdQYrcE4T1jpu}_3n|( zSR+%OnnjzmW$dg^xs`MI%iF*U)4zYSd*H<>yp$6>k?qh*X%yLlJUmc;pmr8R?1`)^Rwf2<%x6g zd(T%!0f)0!fEVPq4R`jwsjT>3;UhKO+}w1n_@bjJUWc~fYB#DO0GPrp5LPcc=mxbv zpWZP|vXk+83;?a44&pW=Ddna_uj+3P%4R7qC42f<@Z_ErpPKX2JU94|{|xC20e~2lM1zV`Th86`;tqbN{=R1g=73j zE)Q?4d?BxfFV$v(tlL+^@bAYUeHgR>vueS+3`Slb5UboM9gOgUD8v#J%#Yk{Z!X}7 zTq}T>aJ)=fB{nDj+2fXS8ke>u@2GGS0Mtv-+i6e zPH?D57yJIMa*|n{n6ep5b=4iym0gt7hKBg?z~$ew*-$W+tasJ&7}y1 z6au`|{?0W`6{nl+yH>nWL=}dwC~)k_J&ILpA1E`Z5AVVfU-;!q4+R$g@l z6)Ht86K!P`m47DSKAb`@dCzHc%lj;*(YQ%f{n_R(l1<`UUwyXoqbW)%;xA+(m>E`{ zp=-N0Up#e?v}C(4{-<*|pxUoHqM9bpYPonqj*~JI)^l%gQGWA%PQk@FF~(2isJvnR z>(zW712ddge`+3IN92Rt3Pzy35{<+-2@O+#mH6GhqX zs>S^Sv)+Q&p%aa@GwXz4a_@s@_V;9@fT%&NUKf~0Uu z!&uaBg)B|e;r^|VnuxKw%nU4KuAq?uZ=a#RR=L~HF^5AN#qgdsQ5pfwO#eD-$w|}F<(1mm2RCb zmQ(h;zB4zL9e3+(9Cz9{RS0J;MN$@{8r?a1KX5u3ypH5_fjgO=wYHgw$U*dcFKXcz zrC6JKtwsVPH_oN>@##(zttQ`E+|XgV-W`?9n0DiH8G`)2( z18cq)FG!g@s=}}TW$n%H5V?_zXTF%szM2)c5wmN{4K@YiX#U>Mxsrl8WxCHAv6{Wu z)HWF}sYW|r?9T$M`(w!fQ_GqYb2PJj?JKFf*R_+94vMJVR-RNi*^R24_98nx>)icL z7kR=TJ-6cau4?d~YqYX_Wrwtxe$`}+8XHFI?)w)vaZgz`n`*X2WKDC4&whn2#_*l% z*y1#3vK%+9{cX1tYC{E6OLHGjwzAXEk02<=dB6hi`w|OVhegre3hvHB?%Qeg!CO`C zIz4}03Ss|B+E0$=`zRbSRRx+CS=!ZDZ{{Ny3xp*BOowdK?6UWuzm_PYFXR0P%R$G~ zEq>X#?|pTBy_po?ruzL7`j+o2eO0GD)41y>4aPD9{9t1(t)L%AIP`}sWGJQh-iBP| zK`XsXtfCfq)7hd~=;`?G>cxC`UVmGKSa>VstKU#OZEs*vCwx22Z|`emfw50JKSo(V z0*0EnNBqQetv@I1z}(2i8`YY?7GC6^)#X&dbCdJ@`z=~-buad+fOeU*qr+px5hDVa zIC-(bA^M75s=L`E-M)G49>Ad%ldivcJ`f_NsmZpSshPFN*<5 z>dNHp5r0w1g0(6%x)Mw6)R?P0v-^`}S}#{qw*B`#2aJ-o!m0g<>bI0^Ooqh6HW>Aa zCuz9#n`~A(Z2CxFSZMs&@`+!PInqMoQvBrI5%&2ojR*c$MW;mseYNir;*_`y4Of}M zg>_ehK0!kUq-@-yD&HDELjAbLn}E)jz2Hi=2yEyD)5T+f&40U`1fK>j^sRT0Y~v?p z_GMLcA4^_L`{qmfuU#vtuPw?a4V5lB6PNN`W@SYm?nyGF_|9}HVw717pScaiC41Jg zYS6#_G9mtvC-=nU?wc<={VnuEp+Xq~bejcD2@HA1nUXYR?*cm8~jR~49J@AG_r zw%bz~_h?x7Lr)g}i84*^m>-n^LqUT$z-=($XSLQ!)4lw1(bCJV0CIBOv(6)PV=`tl z1A`M8mZBc`sXIH0bgi{6I;pkT{|KMc7e4&o&nC)Rfk9XC^N zhwC9*W?zl^8;GnhwqCdQ4H#V8i}#|ZqCH#^m9%r5YdH+2ZIc}Pqbh>VbN3?jtKG^? zV{lUNq{4aVWH)KN;A`2+?;>?y707;kI=)%PVo*81Gc`;pF*jB;Csl-}L|?NRA8Y<@ zw&!QH9!(Lo#ChGsvS79d&swon(pY9SDRF71TA(dv*wNyVPg5aPbLcdze1FfjEzXKY zbt_Oer%TaO$0bvO+mKRXckA#ATe*oV^c$DhLR6Wjgi?1$_v<9~tPvv!n!WZ6#d0I| zj2ZQ37+PbU_Rmal3TR3JNn>}D(F}N3=&QEiq2tb4u||)!_w@D|C~;1rpwlPXzQ^v8)g`DZ5znEf}L;-08w9>GfhFf%!s>dCXy zyn#&3)6pKG$Dd%gOrK;)@GfPa`zvxnsb-JAiA~zIwQLRiIMd{VIqhPCIg}z$>#ZJV zzxEP*1tnb;J5Ls^4+Sd>-;fv0Fp}txogbvLcsH&vjPVM8R#4C60-C-#+-ax;#J)?~(JrI^WZYz>@N< zx#ZTk9(nOlZ%3 zm>GU%cMKPd$0j+9iH8YQxw4XTd^c%wo?kj#CzJ}4&3XBeg!4NsBYU;h+9s@X z)O6N)OMrObbxKgSFO9U z6yQZ9AV17#bsqn`l2v$R!aSOb$=U}+Jmt5kjk2VPXH=5mt?0W?yfT@88Q032{djHG zt-QkWfx1C+^*LfeXXEN006HbL%J&lrhZ2Xfm6hnq&~jI&WxQ8 z*sg=&GFOKU*IW}j{S98%2Ow$X3$}MsW{4Gz%TEoX)BV|+M$=#J*2!fy6AQ^S96Z{nt6hz%|wJq1N+gpqwqWy#OEBPn;P+u8!^Mb3uJZmvjkHl>V z280af%ufP)D$5M?m27sV<#VOZR zpSI3rYz7%IkU2!W0&nZe{r1g$euvr7dxv?@t~fE4Qb%7Kau5TFU!56GRaENt^7Pbi z)e$C(XY~I*NC*tDa}E$rGE*T58w6MiDqkdaG+u$qx_r*bd3je<61G13s|^y+hg+|T zy{#2NrhykIhn4K^ZPT~e{h5x4uD&qNS^Xpjyi3pFNIK+ak=z>GrcU2WfxhOg(7zd! zLPB+voH|fQP{fm%sl~Y2N(QZnxcF z>|>m|*?l1#DDSVOpz!G+hktiW6$-5fUqR4*`Hq0`Es<|?*=vD5s6u^~i$b3!{^_Bi zp{a+VbEhLL>f~O{f&G=tM-?gjQJzXg;RN9H&0-2NlWTT%t}pC*i*;rs7HLkcNJ`xW zkMJnvVC2qr+AVk_pNb2gEpNlWoy_)=HECa*pRThQ#wzAjNSv_-mmh01H{{jUawjU9 zxSdeEtnhj3`(^Dsix}aD93AqL5IfWn#n$A$SzB*~jp_tcLh*IP!z2b}`qUWs6RiTT zy53znS4r1%D#pN8<7Ztk^cG%64_mgL6Jg8kzob=Q{jq^{s7FkSldPG(CJUgrQ^W2Xue zdMvJ|GkGN0giW9d`8_h*{r90Sc4Nc9xYf={>2YpA?HAYYvq_Yri@6<}qFMGr=7W6> z6xAYF-wbRiTgY=}&GpFmp8U#cBLxifMkmn1yKt-{4MG@?+LM#)}TC}$Z z`d(9-Bo(35AyzQJAEV_}cH-q{#moIsI#%2_t(G$%{YEsZ&U!)G(T@AXQ}yIi1imG8ao88#;$8|GM}Yv*iRoX z*bVn(oM0GdO8w4D<}R{2Oknt5ZBGL%cg@$pWafnh}*Bap5Cp-E3(8}PIHs45F z3qq;F;?fNrQR^8QzTX;-egS>z-J>y-f{Q73$cv4mp?G3e72H1O?W|1KnS>_ecq`t+ zPxu?n4Le_d9A3T7*tpY6a3l%Q@-aTdPP1kS<2RUTuftQ1TxqM=Jtm!*1pu7>rcOYFByJTZgjBPSM(lVE6H4h;ncwsk^A+;H4=|}`N-2=L(X>|~ zkbYqnQ*=r3LPWp|9yrup%`*LMb2vMTcw*!GPu_&Ui-iSSy!QL9$3R1?M1X94U8L9U zV>OW(a}c)Ji=ns@V;Gvu1nxPJzKd|08PQJK%Dj%|Yot`84j{&wrznAZ>>V zGcs+%SeQQ$fJ%7j$a_f!e0d<&X^yzgD}9N=5O3;E`+UfM|1Uo(zidnN_^GA(T?Nhp zs*hmy^%dm7jpvHcOEiB$0s{UkFaZbhXf|`d{^ZHOWL(Hox`Ar7F4Ier7!SQhK`{9R zYF9ph0>Sp_U(aJ}NxwV){SLN$LC$HI@cWYF;fw#ioWJ3q@Sh?;@c>U5p9O)AB^R7a zrgq%7q<^tObH8af<33wFM4u7tT=(Jfvz+9x=l=lQgoH2kO}9CAj_8uLTjH;oHdJ83 zE~p-jmc=`YH$HJtMj%$xyv0;%LGE|k#q#f%dR{@yRmQooUgjY&v5`Y@jyqLP;TV2~ zLD8GQi*t^hN+{MX1(sb&*T$1qsq0VA$PNH+O&;pB^A?9rA|@K!Tz$#t!~XSePM+Lb zuj@&4f! zvqF92)9=?b@xpBINjkj68=dMIT^r8js7Embz+JY7>g2v!M8ouDJcC%xZegTY)EddY zAlw4$2Cu$-!bz6WTl)ya*LgU6yn>AIAx#v?W%9i*+dYuz z3INCka#HFOxsN{gp0^`=?DVlO;h;LoQy03%Y;=l>i^G}0(Dn)(8t{?32*{7r*iwQ{ z^(-q8#osmyiYQJ?qhqmgaM&C!AngDpme@BdOY#FX-D4x0KX)3amoccnnAlQ;U*G8#Esi*G?jlIh=QgqB@VU_Ik>r1({&a` zfjXIg`~)1O@#8rag% z)K>LP7}nL&qNoKOY>y}0g63xxd7F7gM#h#E)RiMIw6aSjRyp%CzWfbZqPw`5!@@!N zF5wX9D!6;?&5c7Xq{8+c(e!%y#2rscB3)B(RWl~8$~2I%nGmI&t3ZrHx#JCn8pRYx z5{*N35#1Z0?j=rUv*=a=GFMjBZE2%kfY4Q+P=D3y4TYN+gQTwvdk)1gv6v6WJPvIhI>j|mNQ;+Eu74=$zh%t^7h0WAv( zK4b%nO4dDV_$)cq-uLhtA#x${FOc`H0WY+_q`;^ZDBA3=^Ge<}Gv-E{H+?DJ7G0L? zC`f+80QNG@w!)M#!5)W8LW(uyhBSbW7~iLKRZvpim$@i%$N7}XrX^!)i5 z*{4_8R}eTHVI!-I4~6rk_Poj3XO^F7F%7rMJdMOj8gkJ-Z%9o&56by$rhY9ge$r2= zJgCUx(qPBbd;aJYWzdZkWp|sy(6+KT=GbFt1ajjBuU1kxO||e1ydfo0-V6ZD1;d3= zrp3oktowdwQg)qELsot{Lt30IGmy>2HrE;iK$jGYfU*cH8(ihV`8HjoA$kOlWhT$wb^ zqe@djiHQMAqc-SM@#%)Hu>qtAhT_{%I}0(mn@u9{}Jvx+=C0Byu7B_(8hde-sfA)us zzt($83+^<21!3K^?OD?FyG4ikq6|0D%h^1@vL#KI{93gg(3P$7Hv^Rv2L1D+U!vPs z!aDLNxLhD)Dy3Trb+xGv)vt4BPm~T#HphkZ!f%1q=^&P#->w3-G?wjmT0^PEZUqQh z)Zy6_K(=2VRHbdov)c1qKE~hi_HEGFmrxAs%U6DUKWX?lkO9R1mYIvIJhoKUdDWjU Qz)1uYWK>?2OTP{J9~UZiHiW<{(N#eiW9&!u=ZayoB#mS>OWtIA@Un#a3!>}gp4TkA`}54 z6ms9Yp;7>V2p}OMsO-LcoayF{u7Wu@nVGsaep+<*ju;k2b01#_KKCmfNvOCAu0GDTV&W_?}X?0$6E_;N-{>QbG?4(f&p|8P0OV zjzwCeNv_e5e_PIvY1KI6@o0#4fecku+oHq&rg`F1Kg)FGdK;6HIJr{TBnKIDSPM(F zQL7$mW&;OJ4*k2p%)KpUtK!H}Cr*aAJptZ90sTLE{LzRFtV<$EtmKyx4*~!Ugo2d1 za@4kB_f^q-<@czj8gs+ul&|IaE$UB2aDwt#Ohp0egiW;gH#|)9Uml zbIhtIN!pR5#!`6ozvery_9$56@K)0OoQO0y#KY!DVO&s;3~eU{;BA!^v@%2m)~u^XO`FqK40Mo4YTfSQ6~ysfX8-Qoelnwr79h!Rsm;Ca zGOnY$Hl%^5CfG?`H?<^q6f@|pRv6Z~nva}ogGiqx`cV!xHlpe&Cx#ruXV@0yN*LG& znFQy<16bxh7c`~EK}<)w%(nCoC&JCtg=#A<$J5q2=+*vE^6({( z_vPpawGuJ{w(1SS_RG=DBjFzA&@nHagCjzWCTS+UAmH~!Y@-|wUdpec%7MC>#HEI| z$^p^m#6?lF@CI25HBywL?Dl+|lgVZFu>o;{e{}+Dhskwd6XCgB1uNFBQro=Wt3xuH*V=o4P% zhqk6sY0(dl?&Tg`T`VqJxVU&p+YGK!tL{>W8SToZF0>P7_{~?k*k{i-oa+kPnKxhl zH3ePnj`Rf$fm1e}w!z7D1rI-9N}LF<4P>+m>o=p6OFCV8-M3AEMH}eFLAH$foj(d> zWhoq&FhHg$QdmFAWJ zOV=I=9Ds#YEWPLmfkt%clV)y%j46X73#kt8!qT;BnSYt_f%dy5m_E3oghdbS&lavGkFChndm;tDJN zn4naj%KzKFwesZ|^2*XY@k>CYiK~s4D2?4{KqN)2yTUX+3yeGx$re)6-1kcQL9Gwr z6}^3IX5l+Y-2X9d@fReQP`Z=e5O@|Dr$p^ZAr%!WYmP> z$DmQ}<)g*Y3nGo6z#n?WkfZC?igMBtP4)>qC>%ro^-3GxZ2N{2$f-4MYOZU~_5BKk zlC_kv%S~rBGz<(3e0_b*b=O2-!X=+lw+?@;PQ|)OCL`nny2WV;XG?US#CkSgEz`($=N_XnF8eUAGFT>!8Mn8E&@@G7k*_XP zhY@H}^h#w~bRAi%E(?hrg!vX_%XP|y#K`L-_J473Q1y?h(SjhTSRRiak|a{#U%8x= ztb9FU0B^|rOKT9Yi-{DxSOrECZU-?+RPY>>&F8nX+Q7;^>2uy^3oyq)TP;@VJGsiv=CgZB zrN(BA#`);z2JX9}v5yIqNtOOq5%QO=x!P&9e(aGT{QjSm7waCkqg`1tQ8MN_K*!{w ze%kr0j0QLLg`dFI1x0FyexBFEA zf3>0gCh-Q_H6j#%Yu1=%2fdD&u~$PF)=JY936mzm*Q;)L+fJkH@0g)1SE|Dh`fCAE z(c(-NLSn9w*vq7?E36eR6|V>L zY12g?pdYB7nqsXnaam4)`51FhjMa$AExkk4Hi4Z`5#0Jb9hxEuFEfFYlsI11|T3Hu<~7;Dg*1Y;T_?*Sdh|hB;OW5)|8YB zV?VzC$}{*OR<_~CZi7>e-JD4aH zfhbcJKo_rKfhgrxD8XC#yClTlIXYm?c_(dl8*XW!!D4&6R~L6Z1LYk+GxNf)Y!YUa zGDDVLxAtYaUR+Dlj0NM#*|1#S9zuWVlqEA@8^SefgpOii0&C_QijdYk)E?Mi+gZNI ze)T5nFu&Qr7Me*pYx#(Oxb~T>TZ+_gyGE5t^m4t99pbA+lI_K67!IVA^;x&)`yY`XTU=~{ zndGbs-2s^gk-lZ`^Asu>?Hh@04QopS_z38cY{kZ&_@90Fit8oC!zfXFcp83Hsw<7y zIvC`svkzTa+7>cM{I(Xm&@*%LY>FY;I{*^b(WzCL-&MqM9M$O)a{bcXirDzE9!pGi)=y+dvs0@VGaWK%n- z-P$XAe@@bVTaEfXbPovSr+5rdaG&0gwI%py2L0B(KOArL>U@<3a%UYG-f7P zQoZx|yQGm@)|9aGhhP3r9Di%6k;64Eq1A1huf-JDMi$!*&ytKVGXBOG%2MQC5RUK~ zoEJ>CzR=L~31e}V$zI;6qRd>w3(@e4^4mRWiItNvs}GFf?+N`2=j_Cr5NiYC*-UrT zLJ!oF0&lMpy*wFcMo}kn7OploHz#P;F8Psf3GXDgCY@hZhh%d%cnIY~YR(H;l?M@kACtQJZ+)#Yu+iBbzqgyWB%$OrH0D|r?yFWN0RBP~#=A+>J50zS$|^*$M68vn4Lai$Uf<#J0W*li;O~@eP(Tb#Ac!b-UW(!?>66QAi8y)#ZhN z7|dFXlw8t&g#{QJ^R@0nsQ}!8xxELB_PVIRsrD?rIfmZr#QfXu(NVG3*n~>zmAt8{ z^><_AQ+2N&LEDW{HKlplMmdxtJj07@x+}H502>ScJ}K8~JXjfpdJ|0;`U87I-ERnC z7EJZK;lWLspq^TsAfNx~3)A^`dwP0agi~2VZ6EvRlqk)K^<5Zgi*0yKTyN+0#?!g$ zoWm>fZ>`rdPzi9>eu^##PNrI0$-3OwMIvkYX=!D-y02Akdypp4AWt*=-tSkzLHHT!-=t>{>% ze8vQOEWw2M7f`rV%|gSlvFo?JpRNqqEn0g%=SX}qN*f>X{EOXHB*=aP?!OVEa{m(!tEKb) zuiRp^&rR9w4weKpud^FjaaRv4?h-x}IE! z&1NvdF^WbZtF7z^S&R-7JsqP#UCevnl`FN>V*L_h|JH$rxNvXe>yKKI5|33Cy#LHa z-XzwN@9*z-c6M}TTewdv^T=2JcynKJ& zw~aPNKB?^6x_bcRC{oiGfEq0D9PYi7rNu@~qGD5k4Xc;s&k>LyTMFJC1mPK$@Mr|- zE`_{XMGbm8`}FP6uN$6DSE!-#$=HQ-@e+-~B$Xr$vNW~T*I1M#v!T%H1V7Ln#msif z)lywdS%x313TKkPG{nG~&k*H^)^`;vlF6k0qVirD#s$c$>!R&deRM(QtYCLEEK7td z12#NQAIwDaUQ58&dzy3?DO(Zu`NY!e1;xPz_h)Jdg7>W(P2W}xrTn&2WcezEwwKiFvjpwm4@SV#L zhu`VKgWfwRZ?Kgmk3S_Sv7B-Mez*2PIlDhz9P6=zbZ<@`aKXC2y1C*^NSkRB z4%((<$NrW)j3uNXo?tg*j36`P$Vp;^l~$z5g3$Rr3v{wgs&R943!cNBdQ&4dU&i~i zXLuob3`4XOUYwr5IgY{D`3U*g0qPb+uf2tt4?K}A^^;9pf`=k5KR#p`8gXjocW zdV99PZ#he0@#uN-C~dm{yp`*sIgeA=w!ZCwv*AC#xrLM=^kheSwK6isR_Rbc(~YB= zevce-lr-qj2cG_{dpiQ39q`lUI-D!Qaw+xXcCGTc-gR4TyofSKX%DiLZ!Zw7-i5@@ z53*Sq@=jf|0aI#TJu^8ZL1R9bJYPv_DsN{okR;2l1wVFC7*Ql|>&y!Q^fyAcHoOItTH3vOZNHvtz7-njjlk)tI^)Tl;ia1uw$%(J zCYvp5RwVzV&Oa-~Gk+M}Ho2#W?ozf{kdf`em@Viz?<=3NEBbFFJkw^^(8{0sIcG`h zDoTd-u9ZdR?r_fP?sP4a+ihZac*>lGDhUpym;kfi_x4&5IwZKWNgq_6^5oZfEU)Pb zYm?RqEX3O}>t^DO9j>!|^33p|d(>R3ZLcKJ!ddJ{C_JjM zLbyhB zKTawHD%okC2V1yi&qV-7^gikUweD8G$X)gEb+KpXT@Q+yIpXN8sr3GaynAYemiACd zl;M=VtBvLIe!%uaVOyp0k@`&hr~cc69%0#|XtKCk?$KZ9Aboz0&#+5e2pfTG8fGo> z{~>&CmJd~jb{zroR7si@^ZE?cG+H`3GBfo#WpjsdB;vZw_PG)XWajpEyABo>{Ni&} zUYGYRZlJU04XKxjLd*;)diR$VUIKzkQ-uK9L+HWahcWGDa!S%-lNAo3AsuYJvJP*L zqu;qvx$oN1JJLcISsp`PYq(`W#u%zrH|5{QCY9FPM1RWE!oC=}Wlgkbl$T7^2{o+9 z?beqN{?1Q^hZS>)ee`hiY>0`5kx%-%RrD^1dw$LLuxO$i;`=zz?kBqR(+)%)ZpJlbo1_=-Vebwn}Xi zrI!*$#xDCFnrbxk2#dLeHLO9KdNAhw^FqYNh^T_B2V?Yl5<(O~`;?c%ob zI<{!jrLE`RZN< zoP16bd32}3CK&}KnaAqUam6c|@7%YbtuVO?E~#N=?f8@PY{C-ap3c$Iagfc9Dh-=k zMyWYcfzkcwSk{D=h!Fh%XCYEK2fMfpdZ zmPNxXBn04du|zSMphFzrCWK@Iv@n3Geh^o54pf<(B~8Dno<&~N;NO)#yFPH^3u>3s z)peh)rKqkR`eBi&mj&1av!WF5+C7q4%$(*m{tK@qkI7~V+fWlC3i{o9n9(bA;^`zi4_ySZ zchEeHcJ-rI-H>u&9&0-59})Io>C4NdU^Z!`!otPD)u=tw8UwK&Gi2ywXhRTk5H;HG zAaW7AAw`3s0K|K5=RBysl4E5BLPB4p0v&kdzEG!yM`lRO{J`yxMEl-TpBHTWqJQv; z-OjKZgz~P)0`~p;AUbt#2Y4icFcTl9VJ>*Q$#loC6&LmFLKuf1@c*)sU5Fia&Zs!6 zeu2oU1?w9Zq|Cmp`n;kk#r|8;St;bnh`yX~6a>I)vdM!bKMEk?~N zZ2TupHS&3rR=Cal>yO>FVK|fARKbv0P!8Pex-`K*G)*2T8WYqtKP0Z{;!O8vxVWY_ zO}b0CrejaH=d%v~>!QG|H%(zy$lY2tNqkh>&2S1ccV z7PO&HZCWM|0zhPehAUR=kFp$eVCXc%{$)M$b+t0F*qwotBrt(Q;BBZ27Oo8-i1Pl= z7907e3cT$*p#D>VvP0k)iP`n{D9TPQ=Uw(z;x-~hu)Cha!(ASAYnl~M40g%Z9dv0s?>8UAH~s!8fC~~UhXCZW z*=P%8C{{*EVWkwYa3 zvl&UA4^tMX3$Qt5{XAdltH=@UyX-MPaE(#(E?z3XCD59pt6+4lJol4KT08yN6`O9N zHsv|YgZLxMM{(J+m*G}J8JWwNhsVsS=9#j$i59pIKt8M2{a)W0-yw>h<&@(uFX@!* z^D$j1>_6+CVE^gyo#gUVd5-5$^b*HSzfnye2KVzP+LXyw{p>7-f%!(bg%4cYeLC!Z z_wEInrw{w&{Hu$MGpXcxJGo7p1=>5MM}lfPZ9kk3@i3PUw=sa0pt02+vW||P6aqDn zwVX8$nc5?wuTK&MS(SU2PM`e;VQ7&?cdJbZ!P%WN{AD^Z*-@iq#I^J))X^mlC+Qz4 zLip-_gM6y^9F~-zBtgnKsLk?R zt`G>oWRK^BGMO2T9q6Q`GPx;)=vupK$H zt%tQvD`E^Y%*(#iZ;@5=l|M)^Pl)?9ve0DAS!X%18q)VJ^TTn!(KnQYw@v5ZAw1nk zssd0E^8j7tMD7-s+Q3|gT^B=<7Vr}vfuNFa>pnxg`O1$K0;o_y>w^nSTF58w8sV}9 z+czEs^uC?zWu;Uu60LY2gWG;v!;$s6M$79o+Uy%RYep#=v-1=!s++-j9YXhevc-Di z*V){PCs`ivd`+J3SvMv>4Iz(?KXS?HIMzuYR+6<6^q7_k%)KI>w0tcvpIw26X;!1uQtpvzBfU8bBRskV^q z(u|NS1GJDjv_2lpJyi)NM|N4-yYrKiv2CvMS%ZLe)2Du%2#UcK1LEb~uAG`7|?ZGkdM;}hRXgbCQ~c_!;(L)|MT%3SBAdK{N83rspuLSOs| zF#p)}ukAFl<=VNRz@U(AG`oiHVpv+z{06%Ya`Z;%E>^n^_@6jvN1ldFfY)L#Q+iqF z;l6za#7CiG4el-~4V|8IWweH3w$6)=^YU1P%crID>hQ5%W!m`JS*eM--8cNf zB5T~SQfP+gtxM{}H_hxWG?Q25{o9v3dTCkLSM73Q&Q*lmJ5uS1Yy=CUZ6G=P<Gae}H@ z%=C7-X{wJe53|NU8`sn1X;iUVm>@+*=W^|)63C!O%a7hFj#Q##88p6ni7^kh+s`OMu`g=+3m)x#V=?aEg4SXK(f4(sVO z>y9}Nme(Cwc>EypwUuqLQ56!n(m1X6+DV6(3VvwbgQVp2>ngiEYc|$WOr7t>wyLGa zcbcz5Ds!dS!@~lhy&RTJ@ogjRz(`7r&`eg7Z&>VfagX8xZUfu8I(M?t{*s#*xBa2%1!oyIwjZgk&hc61E+>{= z3D?8Qj^vbTtD#Q#)GgAO%7<5Y3vBA6l0}>FKl^~jLVz8lC4Lh}8@V-_vZIOX4mwbi zEA|rx3V-Cg)Rti<4CyV_LNpuZBbldfeo?FR8kWywGEq0vBi+Vax}8xW*S_u>OnG|p z{Dn3CcXUM{3%{m{R=Q`AFLpI;#Ae)r;_y{A2(Wb)(7Yi3I^3SzPXu?JXY#*ImEJyZ zQ~nNu{u>2(FaHT_>wND8|IGyeAGnkkFu?r(hs6IK-Ex3`+WoU#{~H#;rtnY2|0yi) z@O7_N1l}Gm1$Bfs6EQNPazp$%_q!M5snfT=tvs)Ex4`{BMcDt!@N4_?-wTKQ`nCyV zm&)1a_4)r(g^c7@58dCnvk_bHW>B7M8lxMo6HZj5Mj})iyO@u(1Nlv#f zFR_+fat8z6T_=dgk~;y8skcMCvj$T#P*GX!j*}+GpQnPe*BTrTuVNdmaJE4u#uQ>D zmk1SFT{_;`AYD(ZVLR?OCATo)^H1RWdZ@pt`FS}M)sFPGa2HW{x0J_63gl$9%2*44 z;xcu6kwghlptrdM7hw7E?j1hfOfJ020Ugc?=wwaItea4%;UK`_VDjy6Szkfd*zPq!zX!e&g|@(b^6to93(PTTNL}saNndqu0IjV zU`4wj{jtvPibou$$X-REA#*JXS#SV!Q3oDz)Cd4&`AB7f-E*~*W?|#(c%JGPTFtn6 z^QBkLs?Jr*wKlztlq0>k`u&t3JvqNBzlo874eK!=?$$=M9@=QXgG`TQBxGZjU&~u@ zDzE0;oifApSz`2DD!(rqYmLzrkshn?sP{V|P1lpR$MV7j7BMaU6K^(hGYajelP6&> zmoS*iIOeDnJ^4CWpQ4G!2QkE>oEGhIy|ONR?mW3|PXkM2&V2b0c5_C3D~w(T`zOv%LDYhKbH8U;$#wLW@m&+s!}ZFKXjPXj)Irj>YhG59J~o1&lclT)sNqjE@=IB2=I-=~<6-+uk1>j>?*8Ey)t z+mqxzzZF9S+hvJ~Kr!2MYW;mNB(v!m!OQFX>)G>?)!{d!gn2gHrqWlX(LO@0L+%~% zhjiT5uBRh=602qt1-XW7^T&@%Ic>hicTOE32{~S{slmpMJ#P!t-dYX5p7%@Y8GZ78WKpC~ zTL=GEMNKA|49@e#;f;l1tr9<7*7Wv(gO6$XirSY5@x2K@;@1Jn*hyZspJ*axv^7=x zCAVmkbXpgKBvpKCn;*c9gbdda_&HfWTRH8KN#I5`cQ4^j9KzGaxU3Ya%Pw{z8 zl@vO3!i9DT61-OU@u}>{p6sfTWb^S>WQPYpr3xt+Thv+Gtc6mZUc%d9iT5>w6 zV(&NW`06Pqfwn;6i1}t01s+1HTXxA$5|hTq*Y7=bgMn zq3#$(@;8DzBwpL8r6!RzX6yLAYxHe)qv6|jxC(bwJqI3DN@h{^Bt*aUlsr~*`j?kT zWggvJH=VZJM?+lt7NY6P-%Cd^%7@qN^vB1zr5{CF)K*4uX8Lj!yc)!F6ln@p`X}QR zoh+liUFMZ{y{cbYpADY=V8(R5so@xf+-+SsTI4>axI?RJUFCus#Je$;P4#2FPAbN7 zI!;g!**nyTsjxIVH3r;Q$Qya~((p^CD=F4L3N`eM;})srv(e2Oh5-G#NW1dH)O6xp zZ}%si%x_sZV!;iFqulO z;0HYC$(~YP^mN^;7e$A8Cgo0fN<=0vcqR{}vQBw!J`ps{P}42j+utrIWv92@Uu_^0 zjwUDPn0x?@M^I*4@=s}79581Vx0r|bMPym>*C6g)<$d{c&xu!1}n zu2Kq7IF0vgtL;{^^(OI(sXJ2_$vp#YiwX^r?LN+s3ddc z6pe4av%RyVYod$=FG6>1HLCf0y&K;tH#NbP;*%9s^tybL zgT2{u5D2?5aJ=HTBLye5nqpLjr7n4A%cQ@mZ=ZWIr^A6Adx{28RNhpM!gBgkaIDkD z6Z7lZ!YBM!gNHayo=J`PB@^${AYU_njd(@FW@;z4diJ|vAI%nX;pgj;Y+s&o1>W88 zLii2uK1U0J#9u6u%bI33jXg^Pk0W@-1H+z8p$s!|c^J`LvCnPt)M1%Gdi6VH$j}3R zd|a!1?~ct@_viWVUoSWu!$_&TefqQ)#(!KLsa)KznbDq^JhIoJ$6s8r_x7mq>!1!; zZ1CsM`>q*?&rvxvRc(A4NFcOEMQR-5A&p?}Jfy;7@$w1ZXQlVK3bH?+0h$dY3WJc{ z-f*l~Eg1=l^qGOG4FpWLeM=ja8;xg@wxq8}V5G8&xq8zqrN_s|c@Y^7`-Z!*ov_-Q z9=shDy47H}PF>9s6>$cle2W@Ycmjh@q^l)+lofh)!R^<_MP* zziBB;(@-AGz%l5w83FG(LG_CI%j0*b9eW15sjX#6()dlB0=B7%exl{YvJ}+3y}=y) zAqDVclT%pt@&Y=mF?o044=4M!{RMl_X5$Eal1KnhRQIEZvR zP4C>d1I;{D{Ht;PYpk4hBlYgk*6@Vw%fxykv&dcIAx#et;i%fCW48N+x|(OCmZ4dR z$>>qQtKuK1V-%yBsl3sTU4Lk-al@EcjNAk6Z;$ z-IOcDY$g`T@_w|NEQz1BKkj!2FWR4l6aK%5rJ`3N1>}#=oGrJ5&}TE+QYL{ zn=BsyFb4pHAV^67L}omzG&1U~k-wzngBBgGfbd&ZRRfc$Jlo{5OSczO0E@syv)6v= zD%$kseduIR;Zb17HO^~*?MY~Umxs}~RrIs8Ut>1m`c7m|mHG8*M1iQ!UaXv#&2I2R z;cJZpz2C-)0WJ(J{7H@ev0LTu!prhW3%c#FCx>~JIjb?;rw~4^|*%!5dV{bPvs5VN6r+aNl%ZV+~<5~zJuVdSnz1S zi&|L%9YvGWxGD@T|@BlT9jL?81m_?uxg1-Ji6|Cr;;8a zlYr-%JbQh^JV5VK$j$rw1P>hPHc0D5q?5!YC|FiErrI%V$SoO}+uq&RzgZTFw&!^> z-IdzRayydz;CRPRxPE0e6J+>QbroOKs&TAy{B!x1%8cUY8NNfsAPm6eqwgD(uGe)H zE})yj$dS78J(H@#1N-6AM2jX8fN$!I*Diy70S~B?p~T83ed5bLZ#gTy6pdjPL%{3D z$V&RK8gSA@*kxI&c{(Sk=I|{04{CY<@}2^5#ZA193whL21M^JKMFRwZ5XcIpvV&H+ z;26DHbtG%=6bgUc>^8bh@MEz6xTU<=d{*-i`v-u+UCB^snG_O90 zp5@>*zvR1MSCO4>UT5TOhI^Yz=;S0UaEc^ZSLZFGE|KcnbZrq83r&@?(>~uxa=>Mu4Y@gK+amu9y3}hnNTSK73;~Z%G>i5gu#)}a=@m&_;zYA z4$Tc(cJb(G8ue{K_Cu#D)p-(H0NUMyuft`W25uHR7Q#Ih;bl%mnLYV|3kDGP2YX`@ zrIFvmlVY@BO6yyS7}d-*me|s7_mBw}i^q{K4k|R7sIM27IvyCB^EuSxU9R36dz{S0 zw_)&@Xt)gr7q7{j{Ji9od~wNT%sA9iwgk(KhP@=?{fRH6!@4W>lC7OtRxBU9R?-%V zND~bg%k&61{3>b(e=a0uF4v7{gsu+6l-g8*iIB{u)%EmBx?hV;!A7jNGa+qnKQvcx zb5!$Hn_RNpOlcQ=cBEw;TGodSsNmgbJrro>+t!cV{s~=SPqUw6%Gl@kt)jRxPgh>h zW?ilmGoS%!xiAnh+nmXFMu)oGT5Oz~Rv|*U^59Vw_2lG)x)Tt+{Z0T3EqT4V+-tPW z{6_k!<^pxvvaK-PN2enu>E!lbdLQC(Fp)F19B#%t@;?%;q-h>|AyC_Wj zq~u|Hm}2b0Yjzz4{`UKsZ<(b2I~r?)Gj(@Md;{t%QTHLc&on!Gt!9^7VoN+iHItIw zDmQuV777eBwXK!Ks6T(oXlG!YIGYgv1MwXe5SkzSRHlAgHY^uH^ZnYVR!`p5NZwUX zW}RjcR$|FLh?xq~oIj~lrsC!Kr||ODM8^3A06zeP=jO8aeA{fVPMu2Bq{edh#_qgCXA5PtsIMBx&TfR~cy))9a2{oK{zs@G^XtE zSU`e1nbLT1X}N%L(!zfcutGyaP=)=|HJ2ff5U2KAPHPm zDVAb{*hCEFdz%QLCja$&eKH_tSMVk+#^WZ^sW>I42Tbxj(7zIQbNpvj$emk%_yna#*pdFwI~2 zGBtpagh{_BC@Bx(#0h%-z3!CWw!_JFXDIIbuU|=iX8g?PltKa%@-FWZ zFDmkEmE)b%9MjpXvXYa(`9%EXuXy$e)XL_dprBqIi1Ib8MKS@bfb&1(3j~2X(R+0g zOkDid2jc+Al4kD*rd!Itt3-}|EjO)jEiEl@AzPjX2Cr3*d#eHl!=JuzHIIc=5YpJ7vK+OTC~mFn6dxfHjrSU z28aj`&upI_tp0@k}AC)5J7e~(iW1kdosQ~2-#l6#|6FF z?~CbT0I&QV^#0`$-x+MWIJ4q3;8E3ogR3AA7#uNA+fz@51~g>Mzr%{kXcWWT0j2sh z^kx##0eBSkIu0b~)cT6%Y^Hu{6equAMIe7yVzX5d;F#Yj>|)p%O{#j!sJ>GP9e%%J z)3=a)LiKx=o+fjyFqIIA?XPm4+Gx4Nf}qLlv$fC0YL1mnOp11Z2I%6%8C?RVGzb#p z`Z(&cX%A}mmZ;nFbNjljO{ooqmuA|7-vd!~!y0A@$S1TK=SK`r#-h+}ujenXV@IS= zV1bS1NQ+6iE}NO)+&E3)dI7kL2o4Qcd~kbud#uMKX#SPLCm=;?k&ZzG6x**zLve}~_`!}ymk zUotp-9t#afWoxSPNN2vHkn#`=Z(}D)6)w1ie znw?LR0UQ9Utj?kR@2cu6d~;jM*-bevB_=&MC6M?^Y%_-WgC~ic5;{O6lp@sGMqXLD z-(htsUmOuiSWvKMwnWLUrR1zVrK>qPOHH$M)51f2dyr(EaD`a%0|4_AjrRRY2wXHO z08I6btaZLdR^4K#;PglJ;%TQFFX1kXJ)Fwd=r9>9)8$f}RkwB&M-i@bV};^@-M!#< z=!Dt~UQD+;i+QuAy6n!)@I@)NrR{hAs%2|+W^&+{-Q?}7$J&u9#qv45Zmm5$Jk-_I z1qB6NTv!3C?H*Sl5(z@WLe+kMRa@OWZegA?Td6iW4na$V5a0CdI+|N3Yj2a>T^M1Ox;$qhcZ= zG%p9m;GO{X_jAxlYCj*X2aSgQi48E9fLf=8+k5?=9DMlQ2a|SLIS@G;k)vt-{5RFw zDNmJ;r(D)Wjo62x^Cg%XKwUz9-{-&&@P~6{z}oVrCU$`Ja(#)}WLAY%lURQEKmN;6 z3I~ycd`sZ?lC11|BI5h5(nhkcme zTY(%9p&)?{c)%JO_&pUQ_2fbe8~~a0k810s+V9`LA08fdcMGISyIyRG($iN#A>#bj z`Mb`(l?Fb*^b-baD|z8+($@YIb)5Zl|DT$8N~o#Ka3884@uALA&e6A@)T5-6dGHx4mgp@RtFVJSZ#kgsFtzqG zIiUckU-X#9bL{l~Y6Y^rb}ncK3ZrUg>0G_q1&|PMKS_K&Eo6Q%JH@K=d=KDx8IMEm z%$j9i)&dh^o;P&<lHyhaus_mRi{@6ICY{E`2dJ&pwCH z#d4Ep6gLfu$z4qfGe*B2st)lrx@p_ur)rp>z2(;vy9i$j0RMSL4w(N1$5GsQD{UQ=i^1jWE0-R!@S<-A3w12r-m31 z)*Jr1rpk*eaH+GNNJ~$r##*&{O3rSxW@;v8w1FTZKUkEKlGPonV6snM)5SDdu*SzJ z)c^Wi9dLeiM<;?BY6jAoLif8J6#@WI4ATG%9eO*U4Lkl{LNNRPXCjm4a;MLhPd7^OyC#r5aEhzaXKN~u(fzufR>dh6%O(mHC-&O z7c{Yq(HaeGX@Gv;#~@iaJsK7JPpPV^icJOh>B-5->FMe5^YerEa&nVkGmIhR@3dN| zbg%o1v6{oPv-QCK4qTj_>-Fucj-NSqJuSd8YUEZ)DydetOBQ~=c*M723)_Ns;az{e zN{eA7SZ$tb*nd1eik_{a<4Z3#D3gK%jWeF0b9)LZ5^S>@+JlhEZbrCVgi!RNlsjL& zT9ciQ4*Mh8kJ6qUh=eDSS8NH{6s)Je(ek-)t?A0md%^`U9Dy@eH+91P`Xo2ht!6wR z*h@_axU{?9pWkF$=Iz}4GLZeQ3a=loM~AcFxVpmMK2G_Fa0>sOG)&Hq=f1m5YfH6y z4f^^+^PUj8gS+b(xlyHeOT|WlSD4)SJ?Jq#%1-%a)Q)b9Vj4R5L)Z1PxuEx6ok6jw ztyPU#wC|HoWhMJG#Bvd){}#{apgR%#qjpQ%V<(iYxc_VkG2Ld4X&m;6Ss-lq#)Ws&XBP zTr%DfS=iz__HULF0eY|thI}M*Pnm<88jL>BY>~15N|4fpNvshOCU2Esfc(vxGP#xUR$E) zfw2zy$5lP2Q&I**AvC)pR_X+m(+rISW@JFuWO{ZCd#s=lAjQR@V8bdXpkREsIST4} z>(Vz~jo8lO@ld2QyY?g*M~T@6beprh1594AkQ!<5=29e^Q1}LkAa>nFSP|?x~;Cc}Mn+t%b$M=UALfP3YDtI5Cu-W_Jt3*H|`p?$6 zg;@gwluuBIxPjS(!6B*AHeX?ecJCg9+zBf6LTj18Pa~aO=8A%enV5fr%|rne9iykl zs3sLJ`iw)d(y0G?Y-^X2-(d}s#+LTeS?+@u<7s0dw|H}e&QCMh3MnTgF=Xi zY9wI7!G0G`y94gv;CmJlHg;oWQz=}0JQ3yaH6t06W<%h7MXn4k43cj%FCDQ6%u+;* z>Ur&-w(-o2v0A2nf;^;VlMS#8B!ieIPI#{`TAeU$RlP#r$9l9+)_0=bbN^WzCmMPY ztO_mo!r_Z2n-zTR478wt!(j{F8_)IiF<-^PVS694mD^<>5eSx1fh4lG*8Y*j*jT`l z>I-?_&5`Osl`dF~%~*Z_0Eflj^(4ngeE-+xD|D${-!|OoJP-(6SV#eR5GzuPX3UN{ zWK<(V107mYL9#Z>u;|zfuhdWGwx{81M#-PXJ?x}~%I#bXdJZ>k1@yG75dHzVUQ)71 zcwFzrW4fpE^+EOk01polBPtGSU^9pL?EXe8TmS|O;>n8e(``{K7k&mGBDoyc;=n>; zAtWaX?YoWRscaOu>B+q3*k#_A{d z@?>FtzPuxo#=emhw=<(;CB;TFvz8lSb|qYNJNw2TVu1{0^V*heyOyS10Ed)*yEnvG zLk0M{;&vXb0-^({mAwQJ5YB;4#1FTsIRDJ-p4EoNg1g?nK|&L8F7+%`GnlV@(ro(n z4KY^&?U=S?E+~PVm>EqrGjJQ2+qx{6*37ZLj_-Nf-bG*5f&nza`nJshj+EdM0iHc$ zu*-asrX>zG(Z~WR$)2=3dh00vV4^FPtz>Gx-&c6Z<%bOYvY7H9p1P_3zliz@s5ZK& z+u-h2yoCZS?rw$RTHJ%XyGyZBtTa&E-QC^Y-QC?C-hBVR-g|dt!OA3AncREl$lm*$ z(ar5XnxjoV)n;qh=*oPnu9G|F?{lWJ^&$2jms2?8FnXr5lHiePJZWW6+4_SbdQ7(b z@T}()V72znVBce8CWJKD>YVpJLTaQI4f4-#=eg>fhdhaUSxNs^D_?`V_`FvCKjA+U z4Gn_pc}V-)&sbcqW|&ky(dD{{R=%0ufp{E5mSA^sKN8SKN*Ht!|7?lP7Z3eWVoVwu zQAbvK4Uk;2hzRt}p%a**`D{#e!=o)HC#R+ccLXIAY1*b&sy=b>S(+7tJ?iQddq1B+ zepp7Z$LoPapjnj1SaECHj{A&?#>I!Pr0w_5g1Jl2QGz^T*8d-y2_x=O?EX#WSPl{Y z`eDjuLHOa(>syMOnDWaa6N;RuQIV@>`@nenx^Koe$$j}z>edMO{}BznwN}tuucPz1 zY0V*HA|d}I6UZ=AFkgS`^wB*D$o2Ip0F$SAp|cZlyP`&s1$T#LR!lgnX@nWRc^}Lm zJ>3RMkOg=(to+j^i_h{m(e(SDp~ij)Vuc579Hh;1Dc^CH?XOn3{Hc3z)U%Y=VpQ*v zsEbfXa7kD#RHg|viMohmX#2rdnil%{HSQ3;dL%pHqPKIBEgif%10I{7A?FwLMo==xFDPgN_o_M6|+Zez3>dbvsi?ypfC#5(n^Izj!~$>mH$N;HS# zrCAT2l()s<!*(-GTphVyJCbAZO43uHH_B>0X|;CR_3YvO;YtVynQwBAOoVnaKmoC z8|}-Rfav`fUMh)g9Bh756>@?wf=D}_vs3c5JzO97d$<9|7{`--7>uz8Hd~(gRzHQ` zoHlt}dk_}&ww1Z_L4h6`_ZO#ExjwFEGf0jFN5a$(R5qh3(0mBGIJ^bj76d`B2gg*jFP2~xDc9R>rh>#+-7RdqFx;kUO7efrmvE7s^W z|61;m4O&u6{TrjK^G%B?0;POjg&I<*Lfg5@iVBH|*|aX}5<(eITdDRrkrunE5_Avz zguY3_i0Sm6aq-@W_>=n+6%`c&gIw_}wum!ts#0M|Vd0PeYIoEMRf=XU!Qgd9-KLc% z1;J1Hq-8}mKM_)kXf8P{0=qLY^ zXu%F-~TCj@eA81ANqb|O!m{}h7!31nOX0=n6gm?GR!D5$8o zE2S6807h)gI=PK37&j5I#Fz17xD014^;#sopn2E9273jpu(GVcL)B{R?vD+E|L(ee zx2Ak?T%Iwhq4fQG$HOJFzJGPcsn31Gme&QS!+nO$yj)5=6UwnC57;58C#pJBsQS^BaVmu0g1n1~T``|Yn@oY*R$gySy?6IprHwAvf{(3$dS+G@1qH=V6HW5}8JU^4#|prHZDnrN zW8y+c3^u{@Pc^ zQ_69P+Me~q(|dki1Z@-Fk`kuX)8DOrJZ~b|S+dz_R`G?M59zXO-e)zoQ@Q-U6{xw% z4G>8GpxUzPvKa^E(dxH;GjKCYPB`8@SDG>Jr8F~gagiuTwC`L7wwqxnE5m<1PGZom z+u^35qobptq2c4>8;FH@@B_)8frKSG&=D^g>ivse_%3DsC)_s&8F8HWbwbaV~P4no<)t4+tNj~kpzJ`i( zZ1W%7ZwvFrrfXm)S=4@R?G4OBykq^>EtPvq%?eZ@o^&Q;Yc@}UULV2R6?y?B zq%bsYuR(q%EN!}c)9rVsYg+EYBeh4joxai@8q+=`zDI>NQk z?SjfL7i{*43iT5r;EJg3;oROj$>25fGMr{^oU*$(F8)4gFwWh8?E}StQd2Ikb^gA{ zcl_`riZkkcj4ED+(a}NjW9RCsfMQLJMkVfVFBz~_NiG~R?iWS#udu&mzLw>>UvA*j z^z1tF+}}sHT1O3wAtgQfJ_IfPH#DDDtH=3`{G4fLqu<{C<;fjhKQ!1X4-Z1heYbH- z9o$Y9K0yYjfQ6c#K7_?H`ouu6T*L7G;uON4jCh{i$B`&o)8~T7pm7~;q|D-ewSzR- z01KU&@csLD5*|n6^R?FJyHh^L9Z40Hnb+rgBSS+nes@e9oa>!INU?f3?@X$xC_adK znd7|(6DqX#cFC9FQ+tryi<=9aU@}9&&9D&CBb@X%qIrX0_QgvAs0%9Hg5F&;ey9i` zG8`xG78|PMW;l?>BUq#lvI^1(%*QWqprn+;3EeAP7LR0Pe;D|i!rvk4E}d7aK`(Rc z>HKn8pj9qdRnRJtN`B~>B)^=HP?|}=LHK@KKvHv)qnh(%ui0$ZdlZpZ67(G2Uy~Q^ zqUR}+Jx>Cj8q7XZYK|YgPF_CPekyD;TZTixg=cH^v_Uy9zgwRmiu^$^kIetXdqT1} z{V2cIZR0f?-T!1hy!|4OejKn-_u?wP3H*>vL(7$17lDKATsG1>SzpHYg-;pB)J-CG zEYWna>}P^gcl*D)v#<55x!~cK(iDelEdC7)s5d(NcCB8hvq@H=9UU2=4~|(_U2T<1 z=JXa!_qL#Du}T=-8yFY>4&bQ(Fth_uRjpLW4!9WFIOu_q$)@nf8w$8u$x=rR1=A>e z|K5Ed2|KO~A9OIQqM{c4w_3zYaR$SoLpO8sd`V-VOv81LGX?jZJ}*lB z^kCa6m2TnL5N|8`xT33}TPD=E^=xh$wsaEJzf(VHlp3VR@0zq0Yr@=2kv!;-O?SCh zseJ2U@IWXVwV2~JK}pPI*bVRbwNL*J++O5b|7jjfa*y;O|6eM?$K5K*SWh9w=^VdK zyjhMzwnBKCLs>x`>eV;0HF>gjp{1#6=(uVZ@BYVn%~RsJ;|Z^UKa4JihD^@X|9whf zC+vv$)&i79uE}cOcl7JPxOK2gzhcxB2IR(gT&8qBKAODe&pWl^sbN~p@;-TTre)Bb zZ#EWHB65B<&@utlZcOImTo)McKbF%pV6CY4;v}8kYg=U|gy-CetFkcH$k|TJm|Ahz z^qq4&eaLx%?T+ARFN_plu>IzuJgJLcT|>@w3ryEdZH+P*rKNi_x!Rta$TRy@CRzP( zp%M{=ZZ%T5rmxlG8t})TL%TEMpi(QA|6So{5j5)9T3QyJYNrUh=d+*9gZ)+uEQUeg z!ft4w7s&BksSLohUiMBZob~qfv^>cRz1}EGAL_OH3IIOO{J(W3v0ZOV{rgv>S2cs( z_GEYX>3W}#H8HGn!pkF!*X3xT+0A$LYxLt}?bW*ubo)@0u5~@_Yu{RVJGk-rKs9&p zWJf?Uu_cgkqEFfWlP;V6pip!BiN0OaR#g@1o^|$OaBszj>O>MG$hP>PL@3@IwgY() zsu!6VD&i*VqM_$`?A0)5QZGIN(S6~PqL^Zbd*<`~<@I=jU%J*5+lW<@v$jKBUpSqp zYt2RDlglxT5QZH0GZxj%*_Ye4NA|K(X9MOBm;D5s4<|iq&t^;eN2MnR#D3%g9`1e* zF!M}lWGPa3GBb(Zjk48(G0DXa$9&gfp{tI9{O*6d{n@jhyK zh1)$}4|bAjD%bvo#8*uf?UAw04j7?$-o8^EKV-9==0G?9)0UOSSGVLW44-Lm4PKPZ z8?!cr!iW4E#3#sdC@f<;#?fp9F7ELKM~mBm36sKi!H4F61wqV&-h|$*M`fEYPX`gd zS=wfO%autT8(p54YFTWwzHSi`2<(;o$QF+z;>el;Vutd0I$Y#nkr)UhTdkO#hyg?v zO@kfQV^~>T&6YmCfBiT%Hnvmv-TfZvB98iVE@6!{j}H?RNJmE}R@&qY<_it;f8&oH zUHou3TM@lbB99h?lSVE%a4S-V5)%>jh^vu93px-geD^GchqTA=Q>YPU7^-D03+LTs zi^srh!;Sdi5B2;zogw`z)6=B1cKPu>ay$Nq%kj(p-T;9c9;~`zc|qRUQqy?>unRkp z!rA+}jDg!eXRLf{606O4DH_c2+A15Kf6Ziz2rau7sG~QLxYFpSjR1JoG1-C7XEQiR zDkMH4Muzt>lKakkW-2?s{ZX>RaN##6=--8Xi6%t7NxQzLX}&%6Njp@?7RFqle)3=( zy&eTDUYeq*%j$TW7^uAb(rnm}vsCi)sZONcuDnd0t7!FcBXHU#_owT2e0ie4Rkak@ z&03qXVDNiK(N00pSSiV;LfcZ>Wph_Y*UconX9BbgtLLV?=Zaj3Xzx{-gyo0xBq;=i z=hK}k=E|eR-{peo^|QXzn+vZ-9;0gNqxpwkBYZCe+u39seCh7aO_BK>;!H)1=LwAV z=Xxo0{blyV1Z!P>S$lPtJguf0pR`AZPMe(QBqkE!Zc%%~$l<+PzWJ=hbZ}U*Vw4h5 zT@kCDWG7d`jQR>S;0^!V9KbrpNdA${>_8EM!DJL^6|VRN*au~0WjkS_4wwEWwyG*Mw7+T;kCM(azW#^}ZE7D;jjIdQ%BwZ&vMBuECWHH}mkV^Rc6~!ALBml`c9Nsa#}pccHSW6!E`LsAQ${{q+wc|Ao0PRs zD;}N<%_o?XBAlV!amW(UDm+V(Gdp0V{Ofz^a5jixdA%>BR_Uwnp)r0JC&(4%rJx0q zlFv$$w&s=F|7E_>2er{QFFpNXfAY^{ZA(5Y|M8eci{Sg3-_uchCXE}9wZ?s8=$qlq znOgPnphW%wnQ4_rK<)CIt0&FsDZ0=AAN@=J`82POl3UnX?t8>-N9RvoTr zH??J#72b{|B)Hp%+Cry081nyn72*Ychta*&dp*4$RoPCCT`e95Q*hO0 z+S{F_nt=!y7o%KX>VkiL7ov^@HxGoM5%agafQ)mf0hVex8e_(Az0K$Jq?s!BqtR&q z48qZT`Ff5Nq=f+cQuQMyBAor}(``u!eXZ80F{`TI+v5D{YC@ugVxe*8-%>__sa^3n zrOnh=@5A-sHNM+73PUg9Km(m00;v>P9ZFbO8V#6CdKv`FwcRg|_Ku!LrQY%RzaK90 zD<_UC^`Ycbs~Df2jm~st%E2jei#v6>imkm2x1_jYvJ`2m`urH11hlTEmPe2%av_!E7g2;xvI$^ojFd%DfQdKJe;jT*#A zB7;TNgIo7YXrn&;HU66uDR#yH#gEuwpBWjW<}%m;3tFfW5)`DZW9;x=psB;4v2+N!0K2C%j+q%!I?iFD zaaDrlN>khwg^bhj1;UrHuI@_LQV!A&zg&(t4yBxpJ#y^8?B@QL+cE#(K`8hiDYFN_ zeBZaRhno9JRSN&6mY0fTnghX@mKG66laZ>F|Gl9`I*#@SQlhMQJ`xZqO9GrR(6y3> z1U;}5l)P%Z-KU+*MO>yUzg*@YHYm-#n5A0$m4;QYrdzKWe{*xr`Fc;I4poP-@xu@k z9^KZ&r;()KaDvkKQ0ZVKoL_xZm?Ty@!6HD+zT?;^k_i%S+*xaOvjfh+!NEZ*HEnzw zIY?f`pi~}1I9m-VNS>$`8B{y;DY#(a`Tl&K(E}A1SSZ`W_4amM`Dgi5!3!h3TIA(A z&1nIzt!2A!@C=w5^z`5;DwzsDAy80gw|P(OSCedq_lNChph1*5JD?nZ4C*s0IyfD| zMh+SqR%(o=3y}+Wvh#cma>F4Yh#wgl>FDSHXyc_l=|_f&2g4!P;vdBYuvEc?hBca8 zjErNh-9N<>26wNX8qu#<6X~g`P4`9;bKZf;>SSquOQNywkL)h^kt2hs_5pPy4b9K5 zL<Z-dPaX8r-JOt`lsEV~K%+K9cd6 zCxpDX*hqWh2>x=(AMuR_{$N|JRGWgLm@BoSzmPFZFEjf9p&DGGV3MHYPf?vqM_J>1b&8DIU zNke(LKLT+CZGRwB))aiH64EjM`HdEcurLgG)8{Pc|7PK%AQ=k5-q#Pwi(^Qz2oWS< zL9ir(s2~)AEJqWS5)J4`x;SYF1X5VjYlwu3Ix;r)Z+Mp|GGx$rN)Xlg!827J(DnWO z`!^*eWo32sG{qSy$PJBvfS^=fp_x!I3K`g&By9%|KBL*j*}5KF%0I<5q_UMKc)Z0! z=DJ|69AWuO#mZ-wdXfeiV1!X;4!Ld8#qXzRqT(RD?8S$o@(6(2o2S=9jY9_bmyVUj z93e!p>rpOAneJLE#li}A7T?!eSfcsa*;@c~P~oMd%r@u_0lK(QLlR}Fms!k!J!>l( zAPnTC+uPSodduH3!;PZHsA=Laem68X(@?d6F1C76Kw)8FK&19NEDQ^YJNhqPw-*;S z-(^EdOJ|EtIGKN1XYJ^Zq(v1%S_VTR(tlVik#&jAZ?$}tSmRD>6@650m;u7>^$QJH zTy{$1CiGzWtS^|q;UHn;z8xE#l5)MH$-rv{1|D=M>vN-{k(_f{^!VtZl#sz0%Ub#T z=|gAJYE3ghos!YwLWmloR2UHzRi;|}uiG*dRmWAyp!N?MVOy&70dCAJ{MqOI@C#}O zSJ%A@F(7(eUnlpM{G3Heb3xcNq?bh!cjgh2^cJ7PEM`JvkwPS0W17+ z)oqSkjF|HyZBYY}`WM_H6lh6weyCFQ1X-s3C}lJKf~wMW2CkDhlfxh^fn|EbqGiyi zWu&ExG%B~+F--6SxRP~Km=L}3@WLd206Sz+nx$A*IuRGITnmjAS{l%Fj z5Q--3c^^k8aYY4HINzPc=53Nq!2}+qz^(ya?&!Tu$n)k~h~g2Ok=pw=)u0{Pr;7_` zw^2#Co7?O7;a%z6D*4eOfSU!S$FGty~BZG5W(Kxo&pt#s1^DKA%6xh z&f6P&N#&AoWww>tkWt|SdkuFFJZ>!?O?D1Gpu*SA8CEJ6 zmc_HI>8Zzj9z2@MCCZ;8lU)lI9}J9$enFvXdzhU4W@>^Bo7E)bb4!CRiJ7{SCemA8 z-alG@&Kqs@@sd-fWxG4D?)Xb`Tkx8)4RP~>);~^ZuS#-juCDq0$HZo*%Z!ovT2l$#oSED5y{8>!UOQIF=>gU1O%Zg6-c=B(ZUct4B-JIzL|!apxjux_|Y7E z8#u<-d9~G}NYm6#Sm6Pal`!?0LVS(?H+LsXCUU66A<(8%pD=&>cXw`dYBbMzis315 zLo+AJ0-@8CIlB%NxR8TL4*#RVKoUbE%os3Z3Gk4_Z`wu9)QrG}C^{=Fo2(9_3DkPz!%D1eWTt(??Mzwm<$~Er9uQd%kx+x&JL%tAR1; z*W@zd?Y`4k*|!u=0hos(t6(atXfWcPV1aqPrqr+5l+(ezG=o+|D0oW z8taxvW=#v`z|M-K#kpRqsB*+i@Hj|KtcZ;uxE$e2m_k`P26ou@zln*9d675N6ICWM zjXLsj<8;b}cIaByRgF!TiaY!Q60jeokXks=?RRU_R^mL8*?#ryNp5}wZcjKHIxah$&Y<(@? z^S@TR)Hhn8=c3E=Z2sr@9LJ3>8-B;|9Bw8s2VB02`8zwxT!so~Z&tT4PiFg^wWUL@ z!{hOKFV1TPsT?Z}_%^$1#mKz&Z1&#o@v{%c=KG-$$?E<(j0%#{kl|f2Jzr;yl>}VX zZEBL*wJpUN-q>mt-_7P}LRoQ0tvp$1TuiomXkBa7pu@hC3I}ryNg45^;wDKOr`grGhoXOcjLXH`Vc$B z27VOYk};x}EhWA3+r9f1&0+e1uRbay`aWj+3G^bLqKzig7hL=q zIop2fKec^{9Q`3%e#E|e&-c|5LQCf}dsVu#_4v_&;2NNo@|)>E3U2CvtKYR^;HN@E-z;@B{YzAbN%aREPBy8$YiBp$12U72jtE$YK^Ra&I0VA`V>xVy<a1qM??vMJ|+LJ4eLk?1^ZNbzgW5*m-={*&>!ISBq4U{%5J4jeKj`@wqx+lf zH${pHq*S9pfrCnavT6f+jT2DCL!r68IA11vOU0|Is&k?_4PexwAXZ)l!ckvvG zef~VUwRQM-G^=DZOtRHuR_r1kIi@o;&~ScB`hABr;6hIr4Vz&FRxO29?E0aSm!;)3|PD5j<+D%;Gj=!Ui_B zC{`)|-a`QdZFJJ%oyHFCB4MHIIpW=G=}~FCEhx#CL~dquCs&SJTP2!rZ+5vj8^V2< zP)}(%xW;lly?CV#t1Bz0@S@1Yf7^SM&D^EtwDh4m21p%ks{9RbRAjSNP!FEpM%9!k zEVNUKkky-Vmq~w&oBRTJ=3NIe0skRf|#r-@`jP zg>jOZHr7Kw=zt3~=Hv+KR$i8)x3x$iUyh<>rp;};RL#>))3zU}@&ClzXV)$^r~4(X zi^+-B)^281Yf$vn)cy_8&oK8eZ5f`vQT6o#kIC@C%Sx%sO5iW>pw-MvXLFw*LJheW znV)LO8ya?XD=#eE#R>Zk-O<~-d$l`E?Du{;4)fj==26ozODM}5D3!|rAo_80=Iom6 zjZnP_viOj}Dw%>CQ_IQ=KhJC)MwVX# zs-iia@>0O-rBWP~{=-<(L~dj)mpj=nx8KQiHo6R0G=DP9r7&rtI64-*!-&xCmcJj8 zpAw?NLk3;r;6tKbsO96$6uE)s*t~cG+}35_TGMMTaHS2i{+rcdj%Qp;gLRoiaMHH# ziXEdty<+WawWYKR7-^VSDXW9GuuJ{zp-$=-S9JGv`I_Zwu1Zr8@!gxUZ{B}^P!{Mi8Z1&gOB*L0DV{xj$WHWMw#)oMhf)0_=Eb8o0Ds^jr>3R? zMTW)2bO3T|&wXA}=Cke=pOPYr+GLXDz{bY5y1ELma{ly?_=UyAO$`=mNbUqt%Hx~| zI<8hAPP`NqNYTPfFm%izArBiVaYU(?<{OHm!d27L4vUs?;Ds4;?hF(kOAOLy*qowwc{I#w_XmQQUJ}kD9qn`(0ez zcB$qo0DlvCxH9Bh2KL>mcvj=YTRao^OTYi+0f?GmMGEfo{?F+~&F0DP?5vy9Wwr3N zMf#K(gE|1duqpTF{kWyK#I!2qgKXJiPBq=exEW1y&%0jZRE8}cR=kD!px?2eoqz%5 zc=K(VjD)9(BjeuLm7`W&kRHayP}QwV(tLgCI~Bb+Jfs^d=wNmnlTSINm3T=@5F0;Iiq*mx)XmkbPr>QItRfIRX975h`-#cQo6|t>)-Y}RLjhvm@=%) z@NzRY1{FBJ`=&tE-RA4Pyk3|4HF|R?N&Ob{ejJ3yRZ^ynKAmkB_-d#UU!iDd3GG)ICFFozzZiE_TRJ zjjpV;jODPt%Q&KeZc=#UtZWCr5?i3$26T{xnw&ABwYp55Qm9e>WmO_IrxBpV{D zZLu&HjIi-nM}om}*UZLkUTXx#Uc0bJAGzOHWu8jXRXW-W^v@Di8BsoggvQpU( zX=kXa(3SVhYw=3v&DlqS?ON`&o)Gl&_IbP!)Qw-cv=VqrPuJREn%3{QVY{yqA*wlA zYD5FU%NRG$74PPFnf+^K!M%Q(OR0LS>uxO}!iCm<__=yW8~81*&8yQM)ETG-C9MBZ zHIG8VSiODC5NczK)|7C!dH=4m^kP3a6%_GkcP4Bdox}a=zBp6%^ok$g$`Y;bTOV?H}g3; z9l0$PYVn*tvr-_bpxc=B9BQ4GS=HzRi*u1(O&`8+IKQ7R*{ugz-1`x34DC0=dpCj! z?oQ9=fh=H0?zQ5*n9%h${l!Z&yhxCe7}j0Q(qYvtz$Tc3hD@-^`|rlkmbC5Iw@8E| zFFU9XeGP<$`83y)o~3e~@>dm23j5nqL6_Z2{OP+kLvUQ#*wSf578QuL;RE2~Kpzo)R00+36l`eQ5xFL>vu%tI#Jh^;S|VwRYl*cqY)os9o*xlW?(fOqQ&>i^ToH!X=mr8GQW%1E+qKc>23cT zz^k>#16q}%5S{GmJ3%f-Q+bFvtgS|CtxCUBY+i@CRG1$u7`PhmnL{ZGqSl3Ib33Ac zm7JeaY^vkV`uFgk;kuGE{tS-+56Z-(QTW-?j+iT6Dn4J90Xr2%iiq?zv9Hy8^QpQ3 z)y!-xyhm1g^0)3NZLVVR(AbC)5Eq4oCM%VF;I9$Q9g15|=wtZ7U#|Y6-cEUAPq_(h zP)FJVD^c4rQX3PPsHIwe>HOSWsa&Narre0tUhic?s{hpr$R`St5->q`#C}z~*MZK& zwO;)V_J#7FE3GtylQ!;OZ8=P+W|PQd1{G*@QZWx`AB{=Mw2a|3T=w2N?)+|80N@aE z;9Sr{l}p7p{G<8Wp(3@Zq2s5*&jUIbg!izO&xj`)%89f7+p9dgPcE_vAP_WE6iI-F zY*Ub;p`+tOH4Q*3Xf)%?C4uxu(}mjq$eF`=-)snxrDY8q#3HwC?UfdLR-hlV-4(Lg z^%<*gUU>`f=g3pg_sI7LnqK zvT6?+jDQr-QwK{{Tw|?>zbe6iC2-KVdQm(Z3y{K8*t83O)URIL`N@<;uwMC#V&;VV zKSt{e*wiYxTU+|<6f_7nOMe(Y#U|j<*}n^dYV4x1C`-1gxrt4Ub8=0N&IBYc?w#zG zD=P&JkOFsi=xz3Q)(S%IuRB0?MG4~LcjX5FN3(6pa9pf91cNZv-e&Yw6k+A>CH`oA zl$OY{6)A5ZHo!0hT#zwSyZHtMB3y1j9b$+Ky1#rtKwkhb%b5l*w=}2?3jBI2@O}Au z^G?D~O=~mA4}+OpjR+6$;MdmPZ6qT0g3r#_P!G59q$Xat0L*=jvVw1*jT}=AhqUrj z@P^<^j9gzmqdjDL3MHly_&Ojyh=)ZmI?(`CXfQibmvj;$1sP^2>OVOvuABBpiP_sD zvD?Zzv#$@Tra_e3ZN&uB*E8?CZizA0Tkj_fV-I7QoQrB+ihi7It<*}qo!U-9L+ihl zhkGU|Dvnl4nDvvTk~aDcJ^lD3LvT)?g9aQTSd^C@n?hb-dh4@jz-yCosL@Zux+leL z;FO-1-}`TcI?+SWa=6ySOvghYIG~mG=yX5o*Kc2vOor`Wc|qJf26e4!^dj4R-zCh3 zaj#P1tt%;F+$ZOSx~os;UXf_UigeN}>+zy#K#J8-vE933E0IiFnJ~;C&ha7%8=Erc zrGQVId=6JDtu}q9DYZ2CQ6$*DiE6w1=WoOHsxJwJ$Hg~Kg~Rco3jJmv#k|#{t65zT zb!*8s0iWTGDM*>dt~tXq)b|_yC;PCG|7^3Nex(LIzKpZ8Ga%NJvTF%fDf!jtRC>7D zTxmxR;QI#Fi+|l>MpDCnleClBLs6?)cX%01>3eRq_V&VN&8cO+y&drZWrSU!)gZH8E z2z-X|7uJe)?kNL<_r2DoFShRwDmKZD0OT7dx2(6$W9vwITTe#@gV~@uz0c34`N#b> zY0Xf_SI&ad(w6vvAywlG3T4@x{>Xdz2^=GX6VJ(uj~HOhVUyrc@aeVdB5u0*q(jjY zcxRLJsy^F&{NW+yafsdcg{0bwV6LPxFJE3P6#X$A7t5eXDGu4iK#DMXJTb>;*Er$IeM7B*FgYUE7Yb;(_vD{UGWgm`>}Nb#5=y zk*#8b_IjqbOdEwsyTg-i6Ba?DIlHH}+PbbWT3NyoyZsrv=hsB0`n|$^G^C|=Pq?ea z2-8)quju5kmX!>-9n>O~()C5FW}_PX{f zuE#HB1~BkkPgetiyeKi(Kp15F8`qDWoyKePZV8`6|3Cuel0h4xrq`^!ccsKq_)U&`OzQwEEb8rQc^9L26WNxV6D zAb7|wfy!n6`gC$CC)-)Hg4L-=MO?&-cw(`3R`c>(2#kln7;?Kj+k0Ytq!X^}k%Fzy&kroiyM>Hs>1s1fNB(%_YE~ zKm4=Ipaln{p!tzVVlI4o4f~w|tWYZgdJSf~ zHU24?b4;sw3jUQO+d0(X_`qQXjQ&(Yvb2ZW`H)y#5C+VV_uUI)BYw#T)C3lo_uZ&E zB9<;*QN3?{*%Z$HpP9r{MUrc8)6>%$&y>TreAjC&-?}^i2C8 zRZWA%Y(2#3=XKWKV0qi_R^Qs`2GU`>s`g~P)FEf25^ENxHcM*gjro?wj)*eBmMzKU zpD9)*oVfe30Curcb7T0#^Ep2^zAGR=(Yq`~kKg%wakbeV3}86kCa_9@BeMC0FX8>| zbXBt7ZUF;b-`nJJ45$UfpEg?!x`O!OoNj61F~m*xLVbEnb6K10)*E6dzXo_!J6?nN z6etOP#tlf`oFvlN+b~5#fBAR#tJf5onQ#>J7Y(CcLe5GhTjHL!)F}P)?f@RYU~)gs zfin?Ewk}|4=Q5BR1m9Ywv^#`;O#g*ML%6tZU%NJUiVi`0Sg}r<_Z!b=Yi*&yrqO*4 zXpkjp@a@iv&(|&5Ep1@S*Y#~Z@9OKxN&*^^EDiYQ}qFd=(Pd0R7G zJ7b8&sSAloaFpqJdwrgs#*q^b%vZ5yC7LS-+a$va=W@MWCfhV+usXjnS*b7O0cpM6 zL`G(4D8ivV^d_3qR!^8}v099;d-?|!Xfm=45rY2yYzd4AVu|sYr+~~h4>s2Y=2HmG z%vR--PZaxsm1)(0DsZ!G48uX}4a@foTZo zX46@x-g<3ktbw$CzA)uc;&3z^;=1id5|L^)%t?Q&?pLaxW8M6P{Es+DtX8&04iyKK z3%P#+wYpPIO0frxYL=8|$2bjQHwvGmxzfMZXOv0G%QNn?0_a3jVgTCc$wE&7NPc+;(+oRPU|kNWgWDgY?sW>GA4_v zt61@nsXXkl0Id#^y+fyhkijs%mE=qciEL7kpbxVRQBc?YeFbZGce+B7v6>bb`D7P(8BYmG5wX9DAn`!_tSAbp0;NKI zC`=b)q!NR)QTf!3nL%sFo`tfUI4cYvuzIooHoGS?pnTs5@6Ta6*8R5A{VsOn59Ur= z`EZTI#k+E(s(ha58^8II!OuKqZ-3^H5RNY-IB9$cpW8j7*QQ^nK}zQQR$jk1Qx<74 zt=Q};WkoBpef3=yB+db0V0XJA4gLO}%}43}go!?XJX47ns8;x=7{uMo?eIXs7{7f& z`-5)!hzsrR_S(U96Uv<{vZ0)N(2?7QR~3(C@l!qT4;*G~MFMCJDW83}>{HCF+aGZW^YoIQY`P zgL@tbk~f}!&V}7P4xZs>5m4tOt@~L}$qoGeJB^HNs%qXt%txV~ZELUouq~?tu4BIf z1v9YmYGc!@me-W%mArgvcv#Ulu`hPk2>+=U5?9*kVCH9u( zbJp<52g9YBo7-cH>(a!*rAg15Tw0q0R(k5~Ydsg>E)s)=tV5GLati%ZxoYuNzvoI> zeEIbZ7#%)-{=ZrPwJr+wGRRyjco*(cL3tIXsD}K(LR?%+=?Nt)r?DgtRoJyor&I|B zlNSk!`|>kMK%!E;x8S>gV>g4-;bX|XhHS3YGQS~GopL(1`u#kO&A;n^#x_{v5mi?1e00QU0b z**r=I${#uAdC#TP<^q;C|3c23($-gKNuAxeO$=d0WTXjQTMX9LHziff`3W%6DnRE) zrAOy3blUa01RK>GEm{bAIGuw_J*54=l=lmoZc~N~f%S68h5f*8g+_%P`P&mptEa(^ zF_MqhI;Y#4fB*@vsdM<)=c(iMNDtX{!s()ol5*ttG-@bxJU4C2%ZPXG zMy=S9dZ=TfFffm~#s`Y1AN)(TD}DH8EE7h#-7!NkvPBV4Ni;?@ipnvnl?eH)HSX5^ zmQBUy%o{6Lxf?$*<$H?V2WM-;dd5fFZAeKy+^VPW!a3P4FlJ(khHO-icQ92eq>kLz z`&}hlqi}8cUO?A#W1^Ia?kq0a+MdB7sVxVc8orTe2Us=#V-)>}xpt;))Zq^W6dQHw z|5`eHLX#8`|%Tlr#VRy0yR8tzJL z{8KIWy_jf2&h4A450Ia3Lk3Rm>co1h7yu66to@TkIy6U2X= zn8x)?#SWb9SFW~sC=wW)*E;T0^HB@l140!C#`^v-EVRGpk`qHg0fo}!eyEK1E+>%J zv^&*AVu#_tF-kpTxKG1lb-Fn|cwe$hN-a3snQKRLPHJ6)Pmwj)w$F`w)}c0jRO;=j ze_)sX7^~eEMM?)5?290*HW|hT#2oX-OyIT_fXN3+ByBUYq<4*gOq`(5;2{Wun2|s< zM1KG?g+DA1!C@O7R4}_xjo@{c;pyUh9yOMF$%}@zM5ACR_@;5a(J9l2mTY^(x9{mK zuP4J(5}d8&Y^|{wC_q4s6Gh%1h6AXw{_$%@_eD-Nb2YWCS)3B$FYE5T<0&01VV~^b z38F5_3(26cYE4cVja^yk2&RL7UDOgg-Tj@Rd*nBZGQhjQ$tpRbfxgFMUV5o$^SGw= z2MSksRLUO37^sYG@G5j4U!ddHXzwg~%Fvu*2`^W*f{|~y?O)9oQf$7d9#=0~1M%z@ zi^En=oz1fE%Vqzg`sqp|r0SekNpJ;_WCBl|uJ=ZP64S8NB_MYnN#=^aIYk)Q?&tRY z&>!_Jw`!KEKp8=|Im=7|5!R%+`=xsr^g%pA`)rfw6nr$hE=;F!y+6)$+c$JzzBrb8h=nCfL(`VOZ#C5*om|`l z6h+F9O$~LZRZSFMnepN_IFFi83u{_4qujZevUVDG8B#;vm#+DHypod=Q{7%TJ2?#x z3@8@Q0{y^b<>lL)_RqozkY?5o{u}1BsVONhCz?CJp<1i?Oe*@@!r1>q)>}tq(Z&Cw z5217^-7SsM-AadacS?76i*!kMNq2+NDJ9+A-F^4_JNMjm&pOXy$v-kP&&;0vtxrtW z07+NXwMp*iQ=R2%kIBT%w6_fhe8ne4i4ILZ)fyQl0hQ6uxIE^d!iELg5iw95E7qtj z>{bDXI9X|L?N$M84fS@9YqKnG4%3mJ`%^`WJ6VFh0)X)TH-i@f4FfZl!HYvoEH_Ca zu`tDIHxP4)MYkj=pWM;}&%#>%L4X}Anc3)aC!gPwB}>5h`c}~O)#omWv9gBwi)xa= z!&RM1DZ>?^j$iDsH;eZlDcwy>jTJMGlAk(ixOhjK%ElST3-zA1CnHBz=>n00uRX6X zp+@~cEY7UedImX9e6#g*yoH@_H74H7;;4zXKbrn@*%3P&@)0z0K?azk42?crvU$9> zuGrwBtraOfZ!dk|s^zp+HA$ZCIcc&dZuk|{`r(jB3;qPbw)`mF%PgEr#kqUEnEQQ zN8Sl<>&I&L7ny)VCPzUgg=HHsl8Ja-j!u?a`T6-9ZI%~0ydMJ^F0QU*Zy1RAYxK6){i$Wgi!o9;g6n$X)wk2RFgP9Z$*6icrt0Oh;EZ;d_%D=g z2hxVyC7n+{XEi!toeKoL)TyIm1&fB-?V@H11ZUWkeT5<7$#yim>j)0(q?$4QDxJg? zA+}Odvan~Kr#ifG8L7z#Q4`2wepdpBvSTSq-V?dA6EjcHjaHToYNfV)d25l!12=93 znS+CaVmp%xWLAzO_U;eUHgDm0rc~h;cXpF|&%fSwb*53oZ`WBXHh;V3Fs-FkB9%&D zN%8U-ueTh0D_ZmCjIWk$6FEQx2S)$nPesAiLDmP93UaUbn(Gt6WbBi6PrBqqaag*=D|G8!)=lKN@u9J#|qf1BY5-9;bof z;nJB$)_wY%qx0+Dvvphn!s==e`f-^2Zc;}FepefDxr}I*eWd{TUkC~Yx`JDxY5C24 zlYPqidP52_$Kqk@>8;8^)8(4c6dXs_h*jTmYgpLt_zz8XP}K3>{+jjUg(zV48Bsjx zs%#!iPQK%?#jaH!X?3j^dK+&s$ba}_L&Wk7h8jnuC6X1 zxi}7lOdz5m$asJ{4H#r#)&Z0U9Gag_lVP|qhG>O_;SswAVkM-y3Z$DHwyAa}@+k>< zf3|5ztkKUibk}jN&S8_E$=f@-M4GivWCih`}Z8SE~A5=s3||*Kf%^E z_uZ~u>I#fT?~WK4o3^a9?&71zR9Q?NR_%0jsOy`MI!3G)EBq|;>VB&eUmbRn0ERZ! z!ZRA774TOfsMd|qC)#|iuOIUM%r$H1>nm77umd&Ih>AwN-mcwKkoX8CUX}gp!B2Yp z+vbu(A@JbjP@?r$zviG}Kl|ANtKNJ(|K;>CPn^UUzCeK0^qNHZGyMM__YC50w;>p3 z_!4MuroqT367GJDhZ{9N5lQ)8(%CSxgwnZ0Qg5z(D+C3}Y`hH`bcepZx)E()S6`*b ziNHhVl3WtZx*OaoGz@)&&i?zIn05E=8q+9koavR2OIboG>)F$OC#qFmNkz^k6Gm{K zuhkRM95PG*I32^=(Ah7FCr2{WQwgu_mZH7iv9kC*zj#FJM^`exMeX_RKYnQc%u}J$ zJ(?EweTbeketnWkyTw>%%MR=&0f88V>Gn@u`rJQzLwp=HX# zsWy4-lK7Q7z6^a^IsQ9I*R{lKgc<=g$5?!STA^!k%k2DkKKElM&@lS1%U`g@~W0;JdH z(AO83H7K`#<$$7a?a{7U%5K*jSE7`6*!bu$-TNcG4a4-r@XuKMf@>^ z5ORWGdwR(@us?m0ko!WmSx=`T((VDIj!^Iuy6o?lC!1R8*ggaY+#hKqDHMOg2b%rD z#*`u=inA5hsUQC|n>aavD3@R#*1L0eCn?(6n7&-97&}TM z@mKY<^Wyxaq?bG9;8_h?pG6~6Ak!dkF<5mihbymA{V039w>s1`DV&B`VW)$b!p7iz zT6-kA=_xgI2RkM7cIbGvuqdXJ%uxev; zmL+SVY5l&-;W+cJVl8As-g~Sx*<~^EQ#vixn_P$g7vt@FU*5^2>*)14Y`pJ!*x(bS z^idg`1w*|vQMbJg-u2wqrgA}ozo*xus4IU+yW(}icQQ1DqpuN_-Nww z?QDI>9VkP_aFi}fgF|Og(F6zdsT_Mtw0AKpY6q1TIz*Lb^UcORe=ifgLs%KAWC@0r zl$4Mc7lE#+jZF%vW22-Z`-JiN?RTtjg}k@l{s|o~6ssWF*qruqGbHtmuCyjY;nr)y z2ebR!k-3~`qt!3a@@T3wJNTp=vKxpfiUmb$jwTFFj-}J~&~t*!B4Q912d~xqeAS4X zg2RcvY*GrQoo$c^ZmEIG3&2<-QSKT=0DSPX^RJUMK+z{_as=hw`iAl zmLF5w3kjg<@XBjLX2(u=+I{P@8Xtd;Q{PXQubBH}nubYD7L?pWXIc&mY^FNhVg3dT zCcXA~Fp9LqnwQ>vbtnHaHIM=G8<}wR)r8##!(afBj=Ihi6T_w;i+=YOX8{k3Xr$?9 zXUPABS6{`U$O>|q`{%O>=PV^B;7oC|b<(LyQsV1kqjbT;WQ!Zw_e54uuX()oC-C** zka5*Eh$|#PXz=h_KM8q4B;*6}`$|Ka>{7LkaDO^4-t& zN&NN;h2!H}+j+~$+0@#-OhimP)A3CN~knR1_25*TTL8Q!R+>17vI@S_k!~fOqkq83t zRRkv}aeTEZ2Gdf1rohq@TUpe80Uwqq+iWb0~vWE^ARq@d`Y*Dx;Cme1gk zY$lm&p_+T3RLJjJ_OKIZb1Bb`73FE=3WwmT>>pf-QgrBa}%3b5YtizxWp zt5{^H)fp_ay`|DL8QkU%8yU{8KL;ZgD?s`C!y}7r51mF7G$6B8eBw}jed12*jbpQd z_xk`ew3?*~M2p@uQp?7nlKdSQ*}{~+hHSX<5B@M>Q`R0!JXKY_o8;{*>HG1hEZ{?nL zc8=LcFF1^=T}KyBCmL5X-b`+NaBXGe;y2f_g=ls1|C}zn%;=pN`;#!j*rS$1nxmok zUAZNgn{G=a#o_Bof7U#{d8^a@!MK-YT3D0U-pz8LUeNVurOh^-Qp=Lt2i4>PV~OVg z0X&{|hh>+073Y-YZs^m6*Rlh6?Syhl|1 z@oFPow7wyA(aEyknCfc^Y8nr}0=vb`!ya;bYqV3>Klwq=Mz3#6WTGKfKtcq&$@}3d zh0omq)V>nn@g@rc{&JAT)R8H3Jg{@P-HaYf+|fAv+mDb&iVNYwRx*kB_Qf*GL+(p{ zJ}Fi20d7pD?%Dt&@5oMaAsqetCT%wl5xQVyL|a=o&+dLWAD^?!KnkTRIHBqtp!$mR zo=715IYe@X27mx zY8q?V6P<#v9kf$UnOnaL{1e7~q2l1ca=fx|8BwmmVM%hF7LfdGujNxS)bM+IRWL9z z3&!NcnjM#6D4^|LXtI!u(T023;o$zK-Nl2>pr%*ZdKO_h&0Qv zvBQaxWg;}N++O{W-MwKZ;k|aOh{$3(F_l|#*IfQWy}vQ}LqqC|kX<_yjF~EO#ire9 zqwQ+0Sw@wV3QMx>iTrq)Syc2~pJ!D8>prpw8F(hoUBO5M99HAs>T_~(;;Cg1rgjs_ z_hPw8;oo#Hv#`7?lpS7ZIHu~|J0-c>&H8)1pyQj)vU@8%FQt>YEjOUUTOPQHVam-t zFjB{ZHn1Ht92;+R{Yjw&D7JZ{Iq~2kj~^Pabr}Q3d}15&TU_KSb^Yq!rh&t6LScx} zyaa+o;9>0?0wiE#;SJA$Qq^e{bsT3@rv;@D>D9{Tqu|;s6fAB6x^$FkgVVJVR~Mn) z3fHjQ^amKE05f5Xe@e<*XI6VT>R(eyGtfyX$*ynv`_SXip})WVIo93H%A1msk+D4L zb34j=3W*l%#N7E%lLwd}1HVc4b_E`I8LCr|Rd;=!9w`YeXdH zy(>Du4ev*pnKCH9xVU#-CRCzoYP~b1h*^qG3lVxc2|SpHP)y<#N7;Ky44MIuwX5}% z;{mt(=#L-S8QyCOliT%fs0^lI&G5$o^K>YZE$DHnk%9}VPTomx%i0<3@SxreI-%uY zvi!lEbnZTRX$o#$aUsVDISIJni6xD3iptqcNXG9v)>YIs&g7 zm16ymsYj)L_uX|iNBsgS?H@Ju%276sk98CkYaF(R>gwu1)b|A)Qqlv_^#hYS`%SB8 zB8rq09l4h(PP)$?D7A78A;L&+HPiNJY~<8%oSe0aJuOS8oA4VN{w-;HD8`9x8nQIH zdbO$VthDwQmz6EGFP=B9!qU?A{Gy|HA1|Mni1O1a=qdenUbvMQHI*A~`0EL6Q%(EK zLRg(qZHuDi5QW?a1}*OLwzefdKj|0sh0mc72+|Sz^H{;Fz`SH@A^E{Zp!;PXn~NB> zrqWEGDM_0CGbweH>9pRClKt(D)5LlLiQs+XDV;4u{ag9{aPN=z@kCTFQHIQYErwq; zrF_EakCSoj6T>bzq`3nP^z~`1OA^Dr;?d#$P@|n4s)_f;9)YuFiXMe1<2;!HOmDSn#`U8)(t^KPTO3$o# z&+e}6igulCmIR$HT$Dr|ulIuf0-L`=9VeiZw4Uad{@63AHTer+WO>l3*f!U07w~Sf zw-=Kg?HW!tDNL3$t{Ci(?%5r?hmg3OGPT(KSzB&ZggpHAmpW!^J%i0{PTW@?3qKTu zQ&Bjf<#Om9_z@<4a(S}u6zOH!Vwlp2Qm=k(Ng4m);r8wbp>(MxYWenM8$nKd)pF90 z`p3Z0@q5K5TPKuCHdk|3n&QU0)EBD-ELU4q=qOV@--fw!%NdT_B7e@7to9KcC~QNk zei~kP<}Y`2wLJoylWYZAdTN2_<5fB)g*z2xKacjn-Y4e(~7th7^TX$2|0SNQC@}4-UmX!&zW9((P@PQoot3mq zS}W)dGu8goqN%!N*7f#5evz4&5 zHQ=d)7D{5slg5uwvVKHwHQ4u6ZDe8LxnoVo71;osc4mNtuD}> zo?T%W9*wp*S$vYmE6Y|_=KIj^EGz!By2hkQzad2?(loNI^nwaY`aJcpRGdhG|HZUf zAF5M0&4$QAn$&PoFJ~q39M^_-X6YB5DQ~FDWQbO92jcv^pv;x-8^}8n7#9@j__AIj z*3vn4NOqniwS{7}jD>&cco@?4<0CnG*jtS{^VrhTL!h>|Eyx3)OhAJVpv1zyAWXmp z5z4LnQYq+#-mMqOz{h!>beb}XymCV*X zDvB7GjJu0m{I`+EO|ZE&PaX*sWig50^0S-7uqwkj$Q`An1fZ^B&Shf67sjQhrb_ic zUJ0W?gyiKth(sA`1$4Cj=U}HDv{|P8AF7A!MX>DpUH#fIy zUIHS>e*1Pal5&*HT)>L5J5s&SnrvdI0upJK?vH6+XR*q;ySPv?%i^2~}m49j)GTP$efU5-US6E0rz<8{6 z*iE_?C_(dFlvh4lW-3Vs%m@9Qot*F|uwtt;#-xPp5o%L|pZE7B@o6IajeL1DQ+XB^ z;yNE-nK*uod`q&zi&YR$?kgj>j~+DUurbygAAZ;!4;;LW=jC!PJAEU$&iYQEa!H-! zXL@2Ct)vnSCWB7*dYjjEuJ0>JfgA;~HwhW~FIJx?Hv)pRs;Vk59V^%C6adJwmKKlc zUn6P;!&6fszs+i)AdY<|-^FwS0tcz7on0=klT0gYtCut* z^2jOZL)AXi?z=4QRIkxFahOvR(1mu#3V7j}y}e(zE-%y$7d+V+P4o8lPQFev$Yw!OKGs?lKr?o(rML)AtqX=Zk$sG^x7~$_Ox)%@l zvGK1I6^d=B6tScwI0~j%hH!_It$x+$!9t%;bGu&{_eT*;aFKr8o0uR;W{AzwHEpmV z$^^De8xAuqRlbufmYvo013kw`Z&6O7mUJ{D`pRjU-V#R16%iyRYVdL?-#tw3U;X;0 ztO!(x&dSQqU0fDCJb@!vu4NjE`00gh>(aV@(T=^F^gb@ z`d4fWvWyY~6B7dBibFb7IXV&%sL_v>!T8BmhK5h`Oc8+VL`ys2>|CDUAYzVMYV9pj z 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 literal 0 HcmV?d00001 From 85c3ec89bfcf3e5f46709db3a1b1d4b9b8812de5 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 15:13:07 +0000 Subject: [PATCH 055/158] Moves Changelog from README to CHANGELOG.md and update it --- CHANGELOG.md | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 247 -------------------------------------------------- 2 files changed, 249 insertions(+), 247 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..22e6fd80 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,249 @@ +# Change Log + +### Upcoming changes + +### Release 0.29 (Coming soon) + +- [Upgrades latest parent pom 4.53 and to Jenkins 2.361](https://github.com/jenkinsci/disk-usage-plugin/pull/55) +- [Openrewrite code cleanup](https://github.com/jenkinsci/disk-usage-plugin/pull/57) +- [Clean code using openrewrite CommonStaticAnalysis recipe](https://github.com/jenkinsci/disk-usage-plugin/pull/58) +- [Clean code using openrewrite RemoveRedundantTypeCast recipe](https://github.com/jenkinsci/disk-usage-plugin/pull/59) +- [Removes commented code](https://github.com/jenkinsci/disk-usage-plugin/pull/60) +- [Migrate from junit 3 to junit 4](https://github.com/jenkinsci/disk-usage-plugin/pull/61) +- [Fix unit test that would be stuck in a loop](https://github.com/jenkinsci/disk-usage-plugin/pull/62) +- [Fix URL on images](https://github.com/jenkinsci/disk-usage-plugin/pull/63) +- [Replaces PNG and GIF with SVG and new Jenkins icons](https://github.com/jenkinsci/disk-usage-plugin/pull/64) +- [Refresh UI with new Jenkins look and feel](https://github.com/jenkinsci/disk-usage-plugin/pull/65) +- [JENKINS-30934 - remove dubious Thread.sleep(60000) ](https://github.com/jenkinsci/disk-usage-plugin/pull/66) +- [JENKINS-64375 Disk Usage Plugin uses the deprecated "slave" terminology](https://github.com/jenkinsci/disk-usage-plugin/pull/67) +- [Adds README.md](https://github.com/jenkinsci/disk-usage-plugin/pull/68) + +### Release 0.28 (Oct 01, 2015) + +- Remove excessive logging (JENKINS-30718) + +### Release 0.27 (September 21 2015) + +- Require admin permission to calculate disk space (JENKINS-23100) +- Add disk usage as post-build step  + +### Release 0.26 (September 14 2015) + +- Fix bug where saving configuration resulted in multiple Job Config + History entries (JENKINS-22224) +-   + +### Release 0.25 (January 26, 2015) + +- Plugin doesn't rely on the format of `Run.id` any more ([pull + \#26](https://github.com/jenkinsci/disk-usage-plugin/pull/26)) + +### Release 0.24 (August 5, 2014) + +Partially based on Git commit messages, it is difficult to pair them +with Jira tasks. + +- Update disk usage changelog + ([JENKINS-20604](https://issues.jenkins-ci.org/browse/JENKINS-20604)) +- Add workspace information in plugin main page +- Separate not current slave wokrspace +- Add current state into overall graph +- Separate scale for workspaces +- Enable excluded jobs for disk usage calculation +- Fix size style on job page +- Fix typo + move methods getValue and getUnit into + ProjectDiskUsageActionFactory class + +### Release 0.23 (November 12, 2013) + +Based on Git commit messages, it is difficult to pair them with Jira +tasks. + +- Add test + fix bug which they catch and better line for graphAdd + test + fix bug which they catch and better line for graph +- Reverse build order in graph +- Make graph huger +- Make free space in job directory optional in global graph +- Better sheduling automatic calculation +- Move information about project disk usage form config.xml of job +- Fixing typo direcotory -\> directory +- Display next execution time and add buttom for builds, jobs and + workspaces +- Fix link in menu on main page + +### Release 0.22 (October 18, 2013) + +Based on Git commit messages, it is difficult to pair them with Jira +tasks. + +- Fix tests - HudsonTestCase perform tests in the same jenkins home + directory, so test have to do clean up +- Fix test +- Display all workspaces +- Save history +- Fix backward compatibility, fix concurent modification exception and + make timeout workspace configurable +- Replace Util.isSymlink +- Fix backward compatibility +- Control if diskUsageWithoutBuild!=null +- Check if slaveWorkspacesUsage is not null +- Change developer +- Better colors for graph +- Add backward compatibility +- Add tests and fix bug which test find out +- Correct information about author +- Add tests for case the slave is deleted or workspace of project was + deleted +- Fix problems with claculation threads and removing workspaces form + diskUsage set if do not exist or its slave does not exists +- Add tests +- Fix problems with symlinks +- Add filter for builds age +- Fix issue with graph +- Add e-mail warnings +- Configurable disk usage calculation +- Another type of graph +- Rewrite creation of graphs +- Add funkcionality for counting disku usage of workspaces + tests +- Change behaviour for counting jobs size and builds size + add tests + for it +- Rewriting disk-usage classes structure + +### Release 0.21 (September 9, 2013) + +- Added option for workspace calculation timeout configuration ([pull + \#14](https://github.com/jenkinsci/disk-usage-plugin/pull/14)) +- Added French translation ([pull + \#13](https://github.com/jenkinsci/disk-usage-plugin/pull/13)) +- Don't follow symlinks ([pull + \#12](https://github.com/jenkinsci/disk-usage-plugin/pull/12)) + +### Release 0.20 (June 5, 2013) + +- If workspace doesn't exists, use zero size instead of using previous + workspace ([pull + \#11](https://github.com/jenkinsci/disk-usage-plugin/pull/11)) +- Traditional Chinese translations ([pull + \#10](https://github.com/jenkinsci/disk-usage-plugin/pull/10)) + +### Release 0.19 (March 15, 2013) + +- Fixed link Jenkins management section + ([JENKINS-16420](https://issues.jenkins-ci.org/browse/JENKINS-16420)) +- Fixed root link to preserve protocol + ([JENKINS-15565](https://issues.jenkins-ci.org/browse/JENKINS-15565)) +- Fixed Compute maven module disk usage + ([JENKINS-15534](https://issues.jenkins-ci.org/browse/JENKINS-15534)) +- Setup workspace timeout and added calculation of the build + immediately after the build ([pull + \#9](https://github.com/jenkinsci/disk-usage-plugin/pull/9)) + +### Release 0.18 (September 4, 2012) + +- Fixed DiskUsage dont show values + ([JENKINS-14248](https://issues.jenkins-ci.org/browse/JENKINS-14248)) +- Overall disk usage graph, removed some deprecated methods ([pull + \#8](https://github.com/jenkinsci/disk-usage-plugin/pull/8))  + +### Release 0.17 (May 24, 2012) + +- Added support for hierachical job model ([pull + \#6](https://github.com/jenkinsci/disk-usage-plugin/pull/6)) +- Fixed broken showGraph ([pull + \#7](https://github.com/jenkinsci/disk-usage-plugin/pull/7))  + +### Release 0.16 (April 13, 2012) + +- Fixed wrong URL in LHS menu + ([JENKINS-12917](https://issues.jenkins-ci.org/browse/JENKINS-12917)) +- Fixed possible NPE during Jenkins startup + ([JENKINS-12970](https://issues.jenkins-ci.org/browse/JENKINS-12970)) + +### Release 0.15 (February 26, 2012) + +- Migration from job property to project action which fixed couple of + things + ([JENKINS-12870](https://issues.jenkins-ci.org/browse/JENKINS-12870)) +- Link to disk usage plugin added to main page as /manage is + restricted only for users with admin rights + +### Release 0.14 (June 27, 2011) + +- Fixed NPE + ([JENKINS-8844](https://issues.jenkins-ci.org/browse/JENKINS-8844)) + +### Release 0.13 (March 26, 2011) + +- Japanese translation  + +### Release 0.12 (Oct 22, 2010) + +- Bug fix - workspace disk usage shows wrong values in some cases + ([JENKINS-7867](https://issues.jenkins-ci.org/browse/JENKINS-7867)) + +### Release 0.11 (Jun 4, 2010) + +- Sort functionality + ([JENKINS-3531](https://issues.jenkins-ci.org/browse/JENKINS-3531)) +- Update Build only if disk usage changed + ([JENKINS-5731](https://issues.jenkins-ci.org/browse/JENKINS-5731)) +- Check also workspace for changes +- Calculation interval changed to 6 hours +- Values of sums moved to bottom of table + ([JENKINS-5749](https://issues.jenkins-ci.org/browse/JENKINS-5749)) +- Some typos + ([JENKINS-4691](https://issues.jenkins-ci.org/browse/JENKINS-4691),[JENKINS-5748](https://issues.jenkins-ci.org/browse/JENKINS-5748)) + +### Release 0.10 (Feb 10, 2010) + +- Update code for more recent Hudson + +### Release 0.9 (May 28, 2009) + +- Fixed a problem where prolonged disk usage computation can starve + other timer activities, like polling. + +### Release 0.8: + +- Now works with Hudson ver. 1.293 (for details see + [JENKINS-3340](https://issues.jenkins-ci.org/browse/JENKINS-3340)) + +### Release 0.7: + +- ? + +### Release 0.6: + +- Added sum of values on the top of the overview page. +- Disk usage for build is recalculated each time to reflect artifacts + deletion. +- Default trigger interval prolonged to 60 minutes. + +### Release 0.5: + +- Fixed "Back to Dashboard" link. +- Added option for showing trend graph. +- Fixed and reversed ordering on the overview page (the most space + consuming projects are on the top of the page now). + +### Release 0.4: + +- Fixed NPE. + +### Release 0.3: + +- Icon changed. + +### Release 0.2: + +- First available public release. + +# Missing features and known bugs + +- The trigger interval should be configurable + [JENKINS-13246](https://issues.jenkins-ci.org/browse/JENKINS-13246), + [JENKINS-10116](https://issues.jenkins-ci.org/browse/JENKINS-10116) +- The disk-usage of the whole job should be shown too, because it's a + very important value. +- [All open + issues](https://issues.jenkins-ci.org/secure/IssueNavigator.jspa?reset=true&jqlQuery=project+%3D+JENKINS+AND+component+%3D+disk-usage+AND+resolution+%3D+Unresolved+ORDER+BY+priority+DESC%2C+key+DESC&mode=hide) diff --git a/README.md b/README.md index 76b49d31..ddecb755 100644 --- a/README.md +++ b/README.md @@ -25,250 +25,3 @@ disk usage trend. ![](docs/images/du-project.png) -# Change Log - -### Upcoming changes - -### Release 0.29 (Coming soon) - -- Add support of Disk usage stats for ItemGroups like Folders - ([commit/6bb9c07a051daba18d6975212416eca48ed48743](https://github.com/jenkinsci/disk-usage-plugin/commit/6bb9c07a051daba18d6975212416eca48ed48743)) -- Add disk usage checks of unloaded jobs and builds - ([commit/1c34d56d1508f6c29f8881b7bdc51c194fc96cab](https://github.com/jenkinsci/disk-usage-plugin/commit/1c34d56d1508f6c29f8881b7bdc51c194fc96cab)) -- Remove thread sleep during check rescheduling after changing CronTab - settings blocks "configSubmit" - ([JENKINS-30934](https://issues.jenkins-ci.org/browse/JENKINS-30934)) -- Fixed alignment of project graph - ([JENKINS-30586](https://issues.jenkins-ci.org/browse/JENKINS-30586)) -- Fix image URLs ([PR - \#34](https://github.com/jenkinsci/disk-usage-plugin/pull/34)) - -### Release 0.28 (Oct 01, 2015) - -- Remove excessive logging (JENKINS-30718) - -### Release 0.27 (September 21 2015) - -- Require admin permission to calculate disk space (JENKINS-23100) -- Add disk usage as post-build step  - -### Release 0.26 (September 14 2015) - -- Fix bug where saving configuration resulted in multiple Job Config - History entries (JENKINS-22224) --   - -### Release 0.25 (January 26, 2015) - -- Plugin doesn't rely on the format of `Run.id` any more ([pull - \#26](https://github.com/jenkinsci/disk-usage-plugin/pull/26)) - -### Release 0.24 (August 5, 2014) - -Partially based on Git commit messages, it is difficult to pair them -with Jira tasks. - -- Update disk usage changelog - ([JENKINS-20604](https://issues.jenkins-ci.org/browse/JENKINS-20604)) -- Add workspace information in plugin main page -- Separate not current slave wokrspace -- Add current state into overall graph -- Separate scale for workspaces -- Enable excluded jobs for disk usage calculation -- Fix size style on job page -- Fix typo + move methods getValue and getUnit into - ProjectDiskUsageActionFactory class - -### Release 0.23 (November 12, 2013) - -Based on Git commit messages, it is difficult to pair them with Jira -tasks. - -- Add test + fix bug which they catch and better line for graphAdd - test + fix bug which they catch and better line for graph -- Reverse build order in graph -- Make graph huger -- Make free space in job directory optional in global graph -- Better sheduling automatic calculation -- Move information about project disk usage form config.xml of job -- Fixing typo direcotory -\> directory -- Display next execution time and add buttom for builds, jobs and - workspaces -- Fix link in menu on main page - -### Release 0.22 (October 18, 2013) - -Based on Git commit messages, it is difficult to pair them with Jira -tasks. - -- Fix tests - HudsonTestCase perform tests in the same jenkins home - directory, so test have to do clean up -- Fix test -- Display all workspaces -- Save history -- Fix backward compatibility, fix concurent modification exception and - make timeout workspace configurable -- Replace Util.isSymlink -- Fix backward compatibility -- Control if diskUsageWithoutBuild!=null -- Check if slaveWorkspacesUsage is not null -- Change developer -- Better colors for graph -- Add backward compatibility -- Add tests and fix bug which test find out -- Correct information about author -- Add tests for case the slave is deleted or workspace of project was - deleted -- Fix problems with claculation threads and removing workspaces form - diskUsage set if do not exist or its slave does not exists -- Add tests -- Fix problems with symlinks -- Add filter for builds age -- Fix issue with graph -- Add e-mail warnings -- Configurable disk usage calculation -- Another type of graph -- Rewrite creation of graphs -- Add funkcionality for counting disku usage of workspaces + tests -- Change behaviour for counting jobs size and builds size + add tests - for it -- Rewriting disk-usage classes structure - -### Release 0.21 (September 9, 2013) - -- Added option for workspace calculation timeout configuration ([pull - \#14](https://github.com/jenkinsci/disk-usage-plugin/pull/14)) -- Added French translation ([pull - \#13](https://github.com/jenkinsci/disk-usage-plugin/pull/13)) -- Don't follow symlinks ([pull - \#12](https://github.com/jenkinsci/disk-usage-plugin/pull/12)) - -### Release 0.20 (June 5, 2013) - -- If workspace doesn't exists, use zero size instead of using previous - workspace ([pull - \#11](https://github.com/jenkinsci/disk-usage-plugin/pull/11)) -- Traditional Chinese translations ([pull - \#10](https://github.com/jenkinsci/disk-usage-plugin/pull/10)) - -### Release 0.19 (March 15, 2013) - -- Fixed link Jenkins management section - ([JENKINS-16420](https://issues.jenkins-ci.org/browse/JENKINS-16420)) -- Fixed root link to preserve protocol - ([JENKINS-15565](https://issues.jenkins-ci.org/browse/JENKINS-15565)) -- Fixed Compute maven module disk usage - ([JENKINS-15534](https://issues.jenkins-ci.org/browse/JENKINS-15534)) -- Setup workspace timeout and added calculation of the build - immediately after the build ([pull - \#9](https://github.com/jenkinsci/disk-usage-plugin/pull/9)) - -### Release 0.18 (September 4, 2012) - -- Fixed DiskUsage dont show values - ([JENKINS-14248](https://issues.jenkins-ci.org/browse/JENKINS-14248)) -- Overall disk usage graph, removed some deprecated methods ([pull - \#8](https://github.com/jenkinsci/disk-usage-plugin/pull/8))  - -### Release 0.17 (May 24, 2012) - -- Added support for hierachical job model ([pull - \#6](https://github.com/jenkinsci/disk-usage-plugin/pull/6)) -- Fixed broken showGraph ([pull - \#7](https://github.com/jenkinsci/disk-usage-plugin/pull/7))  - -### Release 0.16 (April 13, 2012) - -- Fixed wrong URL in LHS menu - ([JENKINS-12917](https://issues.jenkins-ci.org/browse/JENKINS-12917)) -- Fixed possible NPE during Jenkins startup - ([JENKINS-12970](https://issues.jenkins-ci.org/browse/JENKINS-12970)) - -### Release 0.15 (February 26, 2012) - -- Migration from job property to project action which fixed couple of - things - ([JENKINS-12870](https://issues.jenkins-ci.org/browse/JENKINS-12870)) -- Link to disk usage plugin added to main page as /manage is - restricted only for users with admin rights - -### Release 0.14 (June 27, 2011) - -- Fixed NPE - ([JENKINS-8844](https://issues.jenkins-ci.org/browse/JENKINS-8844)) - -### Release 0.13 (March 26, 2011) - -- Japanese translation  - -### Release 0.12 (Oct 22, 2010) - -- Bug fix - workspace disk usage shows wrong values in some cases - ([JENKINS-7867](https://issues.jenkins-ci.org/browse/JENKINS-7867)) - -### Release 0.11 (Jun 4, 2010) - -- Sort functionality - ([JENKINS-3531](https://issues.jenkins-ci.org/browse/JENKINS-3531)) -- Update Build only if disk usage changed - ([JENKINS-5731](https://issues.jenkins-ci.org/browse/JENKINS-5731)) -- Check also workspace for changes -- Calculation interval changed to 6 hours -- Values of sums moved to bottom of table - ([JENKINS-5749](https://issues.jenkins-ci.org/browse/JENKINS-5749)) -- Some typos - ([JENKINS-4691](https://issues.jenkins-ci.org/browse/JENKINS-4691),[JENKINS-5748](https://issues.jenkins-ci.org/browse/JENKINS-5748)) - -### Release 0.10 (Feb 10, 2010) - -- Update code for more recent Hudson - -### Release 0.9 (May 28, 2009) - -- Fixed a problem where prolonged disk usage computation can starve - other timer activities, like polling. - -### Release 0.8: - -- Now works with Hudson ver. 1.293 (for details see - [JENKINS-3340](https://issues.jenkins-ci.org/browse/JENKINS-3340)) - -### Release 0.7: - -- ? - -### Release 0.6: - -- Added sum of values on the top of the overview page. -- Disk usage for build is recalculated each time to reflect artifacts - deletion. -- Default trigger interval prolonged to 60 minutes. - -### Release 0.5: - -- Fixed "Back to Dashboard" link. -- Added option for showing trend graph. -- Fixed and reversed ordering on the overview page (the most space - consuming projects are on the top of the page now). - -### Release 0.4: - -- Fixed NPE. - -### Release 0.3: - -- Icon changed. - -### Release 0.2: - -- First available public release. - -# Missing features and known bugs - -- The trigger interval should be configurable - [JENKINS-13246](https://issues.jenkins-ci.org/browse/JENKINS-13246), - [JENKINS-10116](https://issues.jenkins-ci.org/browse/JENKINS-10116) -- The disk-usage of the whole job should be shown too, because it's a - very important value. -- [All open - issues](https://issues.jenkins-ci.org/secure/IssueNavigator.jspa?reset=true&jqlQuery=project+%3D+JENKINS+AND+component+%3D+disk-usage+AND+resolution+%3D+Unresolved+ORDER+BY+priority+DESC%2C+key+DESC&mode=hide) From 555f30b233e0820fa7b885cc57bd1dc87ace6c0c Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 15:23:12 +0000 Subject: [PATCH 056/158] Update images in README and add configuration image Adds shields.io and minor fixes to text. --- README.md | 28 ++++++++++++++-------------- docs/images/du-configuration.png | Bin 0 -> 87428 bytes docs/images/du-overview.png | Bin 28265 -> 157341 bytes docs/images/du-project.png | Bin 78415 -> 147038 bytes 4 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 docs/images/du-configuration.png diff --git a/README.md b/README.md index ddecb755..f6d24cb9 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ +Disk Usage Plugin +========================= + +[![Jenkins Plugins](https://img.shields.io/jenkins/plugin/v/disk-usage)](https://github.com/jenkinsci/disk-usage-plugin/releases) +[![Jenkins Plugin installs](https://img.shields.io/jenkins/plugin/i/disk-usage)](https://plugins.jenkins.io/disk-usage) +[![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins/disk-usage-plugin/master)](https://ci.jenkins.io/blue/organizations/jenkins/Plugins%2Fdisk-usage-plugin/branches) +[![javadoc](https://img.shields.io/badge/javadoc-available-brightgreen.svg)](https://javadoc.jenkins.io/plugin/disk-usage/) + This plugin records disk usage. # Configuration -Showing disk usage trend graph is optional - unselect the "Show disk -usage trend graph" checkbox on the global configuration page ("Manage -Jenkins" -\> "System configuration") if you don't want to see the graph -on the project page. +Showing disk usage trend graph is optional - unselect the `Show disk usage trend graph` checkbox on the global configuration page (`Manage Jenkins` -> `System configuration`) if you don't want to see the graph on the project page. # Usage -When you install this plugin, disk usage is calculated each 60 minutes. -You can see project list with occupied disk space by going to the "Disk -Usage" page in the management section (Dashboard -\> "Manage Jenkins" --\> "Disk Usage"). The same page also allows you to schedule disk usage -calculation immediately. - +When you install this plugin, disk usage is calculated every 6 hours. You can see project list with occupied disk space by going to the "Disk Usage" page in the management section (`Manage Jenkins` -> `Disk Usage`). The same page also allows you to schedule disk usage calculation immediately. ![](docs/images/du-overview.png) -More detailed information can be seen on the project page, where you can -find disk usage for each build and workspace, as well as a graph with -disk usage trend. - +More detailed information can be seen on the project page, where you can find disk usage for each build and workspace, as well as a graph with disk usage trend. ![](docs/images/du-project.png) +You can configurate the plugin in `Manage Jenkins` -> `Configure System` + +![](docs/images/du-configuration.png) \ No newline at end of file diff --git a/docs/images/du-configuration.png b/docs/images/du-configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..6b23e97e61c26cf9336efc1da2d8495caeeb76bb GIT binary patch literal 87428 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 z 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

    aC*h&lH}nFO!<9$#t=Q z{y3xB?-e8A8vg#|+L4hD$EurwB)oQC@i1T_F{EHdrM|Bi|U6oHN=#5_){k z__fim4QwJu;HKWQEJaxP`mlQ1X5&@b#+K2${!=0q<{f()tOv@tExX?GYd?e(m=aef z)8k&$dvC1DlpJxX?X!$9Yi1O!dBx2!AjB<5oo_C=_x*$O^S70oD>B95EjpGcbXn+t zBd^|w&0?XrLW~5n2DHprjC8v8T$uZK+-CRDQZ7WPMX5bTBd^XY9X_-_!+i`ZhLvSw zmS4TS4&dmGAer~Q{kUU4`Hw6HDl$%mo-M-u;X0bL+%j_&zPLCK#I$Ow4EwMbiKa~% z5iF=--8r8G8j3UXVM1$FBSeXs(#@y&S` zta`hjgJ9oM#F3x;a0S>O5IO+|hcF7aLfMT*IwXf>PjAgf6tEqTs9*j5Jg>V5xxN90 zFJ4-1(cEROq=BB)T;c5gR-|>qNVhO<|Kq*;O{3-tXL_bOW?uJ|jI54mYAE-Lln*{A zqHTFMf96j)!sSqLEo?DCVm5l_c7OW!B=;fp6jJ}c zS>rMDQ&}lZh;rhq;PQkI9cc#5e6fcO|eN1I;oX9)Y=VtPNZ1&WOsI^ zH*-uq>4iE}if~^@7_MFexV+5#kCoiXE)j3qZ0_n5#?k7OBOE#_UGQLi=-`ES8$fIZ z1+~fEhY!`*Nr#syJw5}nd2*-=R?bjju65Tgx`!$^uIUPfOHUWl?K&*`sS2O;^4n&(+h?W)8O{e1B~z-NXsIqRAb{<+#zk6t{r|DzIFDo)Mmv>~%G4zC$UZ z-CNUd*xHXg&I&CJuisk6d6HS+TdSKB2|rs()ES&)W+)$Uh&`^~PD}K4BTsgXW%rzl z8_rpqMipe46@a<@T5545&)cP$U4G*W?{WCJyHm2?x|A~!DVce=1^imbiB!XF0sHm} zqinaLX?7~df>_*JOgG52 z?mj1+KS&ZYJX7Pn$FLn~L0xw%TzDJCDGuViKg&8lM(7q&9lpN%zt)}n=0@Sii|)po zKdg(~lK+2pNlA8Hf9gNrp7!l)v_JjX@qFIzpcOZ_WIoopa$DVc*|#2fnH-=KjLYs- zzMo0aR!eK4^5m z(qUBf<-`nw#GqZE0!eK!Ru=Oh>c6Aay>!$buo2=WqqWJNZC_-EuX5JAY z-b#4-5&>qw2Kh~`EaZ7NjCQb>25>|%F;KS?!?B1u$l)fiyOFwj#a9g7Nd6cNq~RP$ ajsMwyXxyGFE$(E^00f?{elF{r5}E)ypkyZi literal 28265 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 z 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 literal 78415 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 z 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 From 1b1f8c1cc2323e07defc032a9eed8039a00d312e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 15:25:31 +0000 Subject: [PATCH 057/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22e6fd80..d0f608fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - [JENKINS-30934 - remove dubious Thread.sleep(60000) ](https://github.com/jenkinsci/disk-usage-plugin/pull/66) - [JENKINS-64375 Disk Usage Plugin uses the deprecated "slave" terminology](https://github.com/jenkinsci/disk-usage-plugin/pull/67) - [Adds README.md](https://github.com/jenkinsci/disk-usage-plugin/pull/68) +- [Improve readme](https://github.com/jenkinsci/disk-usage-plugin/pull/69) ### Release 0.28 (Oct 01, 2015) From dea59d455412758f4faedd0f9cde8aaf4ebb3b13 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 21:28:25 +0000 Subject: [PATCH 058/158] Adds spotbugs ignoreQualityGate to Jenkinsfile spotbugs is failling all builds due major terminology refactor in #67 but without any actual code changes https://github.com/jenkinsci/disk-usage-plugin/pull/67 --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index a84f0c4c..3f8e1f8f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,4 +4,5 @@ buildPlugin( configurations: [ [platform: 'linux', jdk: 17], [platform: 'windows', jdk: 11], + spotbugs: [ignoreQualityGate: true], ]) From 573683b93ceb7083bf1f5b00c708e9852390ab9f Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 21:30:10 +0000 Subject: [PATCH 059/158] Fix spotbugs ignoreQualityGate to Jenkinsfile spotbugs is failing all builds due major terminology refactor in #67 but without any actual code changes https://github.com/jenkinsci/disk-usage-plugin/pull/67 --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3f8e1f8f..31e224b3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,5 +4,6 @@ buildPlugin( configurations: [ [platform: 'linux', jdk: 17], [platform: 'windows', jdk: 11], + ], spotbugs: [ignoreQualityGate: true], -]) +) From 373f1b1bcfa3086427a7af37c581657a3ddcae11 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 01:11:55 +0000 Subject: [PATCH 060/158] Adds spotbugs ignoreFailedBuilds to Jenkinsfile spotbugs is failing all builds due major terminology refactor in #67 but without any actual code changes https://github.com/jenkinsci/disk-usage-plugin/pull/67 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 31e224b3..274221ec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,5 +5,5 @@ buildPlugin( [platform: 'linux', jdk: 17], [platform: 'windows', jdk: 11], ], - spotbugs: [ignoreQualityGate: true], + spotbugs: [ignoreQualityGate: true, ignoreFailedBuilds: false], ) From da81d5592d75b07b983e6e981e93554dfc4eb966 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 20:02:30 +0000 Subject: [PATCH 061/158] Removes deprecated maven property java.level java.level is no longer the way to set the required java version https://github.com/jenkinsci/plugin-pom/pull/522 --- pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pom.xml b/pom.xml index 3c8989ef..ae633b5e 100644 --- a/pom.xml +++ b/pom.xml @@ -27,10 +27,6 @@ HEAD - - 11 - - org.jenkins-ci.plugins From 5d66a4d7e5383b2dd7c683341728717ff76040c7 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 19:39:07 +0000 Subject: [PATCH 062/158] Order builds by build number for graph show in project page --- .../disk_usage/ProjectDiskUsageAction.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 02ad47f3..857eaeb6 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -18,6 +18,8 @@ import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; import jenkins.model.Jenkins; import org.jfree.data.category.DefaultCategoryDataset; import org.kohsuke.stapler.export.ExportedBean; @@ -302,8 +304,10 @@ public Graph getGraph() throws IOException { Long jobRootDirDiskUsage = getJobRootDirDiskUsage(); maxValue = jobRootDirDiskUsage; // First iteration just to get scale of the y-axis - ArrayList builds = new ArrayList<>(); - builds.addAll(property.getDiskUsageOfBuilds()); + final var builds = property.getDiskUsageOfBuilds() + .stream() + .sorted((a, b) -> b.getNumber() - a.getNumber()) + .collect(Collectors.toList()); // do it in reverse order for(int i = builds.size() - 1; i >= 0; i--) { DiskUsageBuildInformation build = builds.get(i); @@ -320,16 +324,12 @@ public Graph getGraph() throws IOException { double workspaceBase = Math.pow(1024, workspaceFloor); DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset dataset2 = new DefaultCategoryDataset(); - for(Object[] usage: usages) { - Integer label = (Integer) usage[0]; - dataset.addValue(((Long) usage[1]) / base, - Messages.DiskUsage_Graph_JobDirectory(), label); - dataset.addValue(((Long) usage[2]) / base, - Messages.DiskUsage_Graph_BuildDirectory(), label); - dataset2.addValue(((Long) usage[3]) / workspaceBase, - Messages.DiskUsage_Graph_AgentWorkspaces(), label); - dataset2.addValue(((Long) usage[4]) / workspaceBase, - Messages.DiskUsage_Graph_NonAgentWorkspaces(), label); + for (Object[] usage : usages) { + String label = "#" + (Integer) usage[0]; + dataset.addValue(((Long) usage[1]) / base, Messages.DiskUsage_Graph_JobDirectory(), label); + dataset.addValue(((Long) usage[2]) / base, Messages.DiskUsage_Graph_BuildDirectory(), label); + dataset2.addValue(((Long) usage[3]) / workspaceBase, Messages.DiskUsage_Graph_AgentWorkspaces(), label); + dataset2.addValue(((Long) usage[4]) / workspaceBase, Messages.DiskUsage_Graph_NonAgentWorkspaces(), label); } return new DiskUsageGraph(dataset, unit, dataset2, workspaceUnit); } From 7f162b5dda97ff256fe08cfb6ec3719edfd8c767 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 01:35:49 +0000 Subject: [PATCH 063/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f608fc..a56ddf82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - [JENKINS-64375 Disk Usage Plugin uses the deprecated "slave" terminology](https://github.com/jenkinsci/disk-usage-plugin/pull/67) - [Adds README.md](https://github.com/jenkinsci/disk-usage-plugin/pull/68) - [Improve readme](https://github.com/jenkinsci/disk-usage-plugin/pull/69) +- [Removes deprecated maven property java.level](https://github.com/jenkinsci/disk-usage-plugin/pull/71) ### Release 0.28 (Oct 01, 2015) From 792182e6408f62174f215a8d053efa13a7f18fec Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 02:00:43 +0000 Subject: [PATCH 064/158] Removes unused DiskUsageRecord --- .../plugins/disk_usage/DiskUsageRecord.java | 87 ------------------- 1 file changed, 87 deletions(-) delete mode 100644 src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java deleted file mode 100644 index 1e034a5d..00000000 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageRecord.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package hudson.plugins.disk_usage; - -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * - * @author Lucie Votypkova - */ -public class DiskUsageRecord { - private Long date; - private Long diskUsageBuilds = 0L; - private Long diskUsageJobsWithoutBuilds = 0L; - private Long diskUsageWorkspaces = 0L; - private Long allSpace = 0L; - private Long diskUsageNonSlaveWorkspaces = 0L; - - public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonSlaveWorkspaces) { - this.diskUsageBuilds = diskUsageBuilds; - this.diskUsageJobsWithoutBuilds = diskUsageJobsWithoutBuilds; - this.diskUsageWorkspaces = diskUsageWorkspaces; - this.allSpace = allSpace; - this.diskUsageNonSlaveWorkspaces = diskUsageNonSlaveWorkspaces; - date = System.currentTimeMillis(); - } - - public Long getBuildsDiskUsage() { - if(diskUsageBuilds == null) { - return 0l; - } - return diskUsageBuilds; - } - - @Deprecated(forRemoval = true) - public Long getNonSlaveWorkspacesUsage() { - return getNonAgentWorkspacesUsage(); - } - - public Long getNonAgentWorkspacesUsage() { - return diskUsageNonSlaveWorkspaces; - } - - @Deprecated(forRemoval = true) - public Long getSlaveWorkspacesUsage() { - return getAgentWorkspacesUsage(); - } - - public Long getAgentWorkspacesUsage() { - return diskUsageWorkspaces - diskUsageNonSlaveWorkspaces; - } - - public Long getJobsDiskUsage() { - if(diskUsageJobsWithoutBuilds == null) { - return getBuildsDiskUsage(); - } - return diskUsageJobsWithoutBuilds + getBuildsDiskUsage(); - } - - public Long getAllSpace() { - if(allSpace == null) { - return 0l; - } - return allSpace; - } - - public Long getWorkspacesDiskUsage() { - if(diskUsageWorkspaces == null) { - return 0l; - } - return diskUsageWorkspaces; - } - - Date getDate() { - final SimpleDateFormat sdf = new SimpleDateFormat("d/M"); - return new Date(date){ - private static final long serialVersionUID = 1L; - @Override - public String toString() { - return sdf.format(this); - } - }; - } -} From 6b3707385cbc5e9c847bccc99bc71b1fe9947fab Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 02:20:56 +0000 Subject: [PATCH 065/158] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a56ddf82..3b41d5e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,6 @@ ### Upcoming changes -### Release 0.29 (Coming soon) - - [Upgrades latest parent pom 4.53 and to Jenkins 2.361](https://github.com/jenkinsci/disk-usage-plugin/pull/55) - [Openrewrite code cleanup](https://github.com/jenkinsci/disk-usage-plugin/pull/57) - [Clean code using openrewrite CommonStaticAnalysis recipe](https://github.com/jenkinsci/disk-usage-plugin/pull/58) @@ -19,6 +17,8 @@ - [Adds README.md](https://github.com/jenkinsci/disk-usage-plugin/pull/68) - [Improve readme](https://github.com/jenkinsci/disk-usage-plugin/pull/69) - [Removes deprecated maven property java.level](https://github.com/jenkinsci/disk-usage-plugin/pull/71) +- [Order builds by build number for graph show in project page](https://github.com/jenkinsci/disk-usage-plugin/pull/70) +- [Removes unused DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/72) ### Release 0.28 (Oct 01, 2015) From 6781f4f23949d5de799769d276fea64567d450ab Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 8 Feb 2023 16:58:04 +0000 Subject: [PATCH 066/158] Fixes Correctness category identified by spotbugs --- .../disk_usage/BuildDiskUsageAction.java | 12 ++-- .../disk_usage/DiskUsageBuildInformation.java | 15 +++-- .../disk_usage/DiskUsageManagement.java | 4 +- .../DiskUsageProjectActionFactory.java | 2 +- .../plugins/disk_usage/DiskUsageProperty.java | 10 +-- .../plugins/disk_usage/ProjectDiskUsage.java | 6 -- .../disk_usage/ProjectDiskUsageAction.java | 66 +++++++++---------- .../plugins/disk_usage/Messages.properties | 6 +- .../plugins/disk_usage/Messages_fr.properties | 7 +- .../plugins/disk_usage/Messages_ja.properties | 7 +- .../disk_usage/Messages_zh_TW.properties | 7 +- .../integration/DiskUsagePropertyTest.java | 3 +- 12 files changed, 75 insertions(+), 70 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index db620a4d..f5b04d74 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -1,5 +1,6 @@ package hudson.plugins.disk_usage; +import hudson.FilePath; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; @@ -40,11 +41,11 @@ public String getIconFileName() { } public String getDisplayName() { - return Messages.DisplayName(); + return Messages.displayName(); } public String getUrlName() { - return Messages.UrlName(); + return Messages.urlName(); } public void setDiskUsage(Long size) throws IOException { @@ -123,9 +124,12 @@ public Object readResolve() { Node node = build.getBuiltOn(); if(node != null && diskUsage.wsUsage != null && diskUsage.wsUsage > 0) { DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - AbstractProject project = build.getProject().getRootProject(); + AbstractProject project = build.getProject().getRootProject(); if(property != null && (project instanceof TopLevelItem)) { - property.putAgentWorkspaceSize(node, node.getWorkspaceFor((TopLevelItem) project).getRemote(), diskUsage.wsUsage); + final var workspaceFor = node.getWorkspaceFor((TopLevelItem) project); + if (workspaceFor!=null){ + property.putAgentWorkspaceSize(node, workspaceFor.getRemote(), diskUsage.wsUsage); + } } } diskUsage = null; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index 4683c78b..e9b72d0d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -8,12 +8,13 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Objects; /** * * @author Lucie Votypkova */ -public class DiskUsageBuildInformation implements Serializable, Comparable { +public class DiskUsageBuildInformation implements Serializable, Comparable { private static final long serialVersionUID = 1; @@ -71,9 +72,15 @@ public boolean equals(Object o) { return false; } - public int compareTo(Object o) { - if(o instanceof DiskUsageBuildInformation) { - return id.compareTo(((DiskUsageBuildInformation) o).getId()); + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public int compareTo(DiskUsageBuildInformation o) { + if(o != null) { + return id.compareTo(o.getId()); } throw new IllegalArgumentException("Can not compare with different type"); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 97842688..8bb5e767 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -27,7 +27,7 @@ public String getIconFileName() { } public String getDisplayName() { - return Messages.DisplayName(); + return Messages.displayName(); } public String getUrlName() { @@ -36,7 +36,7 @@ public String getUrlName() { @Override public String getDescription() { - return Messages.Description(); + return Messages.description(); } public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 2d411e12..dbfe9539 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -280,7 +280,7 @@ public String getValue(String size) { @Override public String getDisplayName() { - return Messages.DisplayName(); + return Messages.displayName(); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 8c884af6..3b3b3002 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -298,7 +298,9 @@ public void checkWorkspaces(boolean force) { } } catch (Exception e) { - LOGGER.warning("Can not check if file " + path.getRemote() + " exists on node " + node.getNodeName()); + if (path != null) { + LOGGER.warning("Can not check if file " + path.getRemote() + " exists on node " + node.getNodeName()); + } } } } @@ -405,8 +407,8 @@ private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path public Long getAllWorkspaceSize() { Long size = 0L; for(String nodeName: getAgentWorkspaceUsage().keySet()) { - Node agent = Jenkins.getInstance().getNode(nodeName); - if(agent == null && !nodeName.isEmpty() && !(agent instanceof Jenkins)) {// agent does not exist + Node agent = Jenkins.get().getNode(nodeName); + if(agent == null && !nodeName.isEmpty()) {// agent does not exist continue; } Map paths = getAgentWorkspaceUsage().get(nodeName); @@ -507,7 +509,7 @@ public DiskUsageDescriptor() { @Override public String getDisplayName() { - return Messages.DisplayName(); + return Messages.displayName(); } public boolean showGraph() { diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 1f38ab13..93ef9d24 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -185,12 +185,6 @@ public synchronized void load() { } try { file.unmarshal(this); - if(buildDiskUsage instanceof HashSet) { - // saved collection is not serialized in previous versions. - Set informations = new CopyOnWriteArraySet<>(); - informations.addAll(buildDiskUsage); - buildDiskUsage = informations; - } } catch (IOException e) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to load " + file, e); } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 857eaeb6..9c959a03 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -43,11 +43,11 @@ public String getIconFileName() { } public String getDisplayName() { - return Messages.DisplayName(); + return Messages.displayName(); } public String getUrlName() { - return Messages.UrlName(); + return Messages.urlName(); } public Long getDiskUsageWorkspace() { @@ -230,42 +230,42 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx Long buildsDiskUsage = 0L; Long locked = 0L; Long notLoaded = 0L; - if(project != null) { - if(project instanceof ItemGroup) { - ItemGroup group = (ItemGroup) project; - Map sizes = getBuildsDiskUsageAllSubItems(group, older, yonger); - buildsDiskUsage += sizes.get("all"); - locked += sizes.get("locked"); - notLoaded += sizes.get("notLoaded"); + + if(project instanceof ItemGroup) { + ItemGroup group = (ItemGroup) project; + Map sizes = getBuildsDiskUsageAllSubItems(group, older, yonger); + buildsDiskUsage += sizes.get("all"); + locked += sizes.get("locked"); + notLoaded += sizes.get("notLoaded"); + } + Set informations = property.getDiskUsageOfBuilds(); + for(DiskUsageBuildInformation information: informations) { + Date date = new Date(information.getTimestamp()); + if(older != null && !date.before(older)) { + continue; } - Set informations = property.getDiskUsageOfBuilds(); - for(DiskUsageBuildInformation information: informations) { - Date date = new Date(information.getTimestamp()); - if(older != null && !date.before(older)) { - continue; - } - if(yonger != null && !date.after(yonger)) { - continue; - } - Long size = information.getSize(); - buildsDiskUsage += size; - Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); - AbstractBuild build = null; - for(AbstractBuild b: loadedBuilds) { - if(b.getId().equals(information.getId())) { - build = b; - } - } - if(build != null) { - if(build.isKeepLog()) { - locked += size; - } + if(yonger != null && !date.after(yonger)) { + continue; + } + Long size = information.getSize(); + buildsDiskUsage += size; + Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); + AbstractBuild build = null; + for(AbstractBuild b: loadedBuilds) { + if(b.getId().equals(information.getId())) { + build = b; } - else { - notLoaded += size; + } + if(build != null) { + if(build.isKeepLog()) { + locked += size; } } + else { + notLoaded += size; + } } + diskUsage.put("all", buildsDiskUsage); diskUsage.put("locked", locked); diskUsage.put("notLoaded", notLoaded); diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages.properties b/src/main/resources/hudson/plugins/disk_usage/Messages.properties index ef6b1bb2..949a88b9 100755 --- a/src/main/resources/hudson/plugins/disk_usage/Messages.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages.properties @@ -1,6 +1,6 @@ -DisplayName=Disk Usage -UrlName=diskUsage -Description=Displays per-project disk usage +displayName=Disk Usage +urlName=diskUsage +description=Displays per-project disk usage DiskUsage.Graph.JobDiskUsageAxis=job, builds DiskUsage.Graph.WorkspaceDiskUsageAxis=workspaces diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages_fr.properties b/src/main/resources/hudson/plugins/disk_usage/Messages_fr.properties index 46e45e54..4fb2c3d9 100644 --- a/src/main/resources/hudson/plugins/disk_usage/Messages_fr.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages_fr.properties @@ -1,4 +1,3 @@ -DisplayName=Utilisation du disque -UrlName=diskUsage -Description=Affiche l''utilisation du disque pour chaque projet -ProjectDiskUsage=Utilisation du disque +displayName=Utilisation du disque +urlName=diskUsage +description=Affiche l''utilisation du disque pour chaque projet diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages_ja.properties b/src/main/resources/hudson/plugins/disk_usage/Messages_ja.properties index c3d0d753..06e811c0 100755 --- a/src/main/resources/hudson/plugins/disk_usage/Messages_ja.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages_ja.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -DisplayName=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf -UrlName=diskUsage -Description=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf\u3092\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3054\u3068\u306b\u8868\u793a\u3057\u307e\u3059\u3002 -ProjectDiskUsage=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf +displayName=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf +urlName=diskUsage +description=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf\u3092\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3054\u3068\u306b\u8868\u793a\u3057\u307e\u3059\u3002 diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages_zh_TW.properties b/src/main/resources/hudson/plugins/disk_usage/Messages_zh_TW.properties index 655151e7..dd5a1e62 100644 --- a/src/main/resources/hudson/plugins/disk_usage/Messages_zh_TW.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages_zh_TW.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -DisplayName=\u78c1\u789f\u7528\u91cf -UrlName=diskUsage -Description=\u986f\u793a\u500b\u5225\u5c08\u6848\u7684\u78c1\u789f\u7528\u91cf -ProjectDiskUsage=\u78c1\u789f\u7528\u91cf +displayName=\u78c1\u789f\u7528\u91cf +urlName=diskUsage +description=\u986f\u793a\u500b\u5225\u5c08\u6848\u7684\u78c1\u789f\u7528\u91cf diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 4c9e6045..ba87c69d 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -12,6 +12,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.annotation.Annotation; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRecipe; import hudson.XmlFile; import java.util.logging.Level; @@ -529,7 +530,7 @@ private void checkForConcurrencyException(Exception exception) { fail("Checking of thread safety caused Exception which is not connected with thread safety problem."); } - // JENKINS-29143 + @Issue("JENKINS-29143") @Test public void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation() throws Exception { final FreeStyleProject project = j.createFreeStyleProject(); From a71a5a558c9b1a5a0ee3d65e9223294a4c0bbb72 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 02:59:59 +0000 Subject: [PATCH 067/158] Fix inefficient use of keySet iterator instead of entrySet iterator --- .../plugins/disk_usage/DiskUsageProperty.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 3b3b3002..c9490abb 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -8,6 +8,7 @@ import hudson.init.Initializer; import java.io.File; import java.io.IOException; +import java.util.Map.Entry; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; @@ -215,9 +216,9 @@ public Long getWorkspaceSize(Boolean containdedInWorkspace) { continue; } Map paths = getAgentWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()) { - if(containdedInWorkspace.equals(path.startsWith(workspacePath))) { - size += paths.get(path); + for(Entry entry : paths.entrySet()) { + if(containdedInWorkspace.equals(entry.getKey().startsWith(workspacePath))) { + size += entry.getValue(); } } } @@ -362,7 +363,7 @@ public Long getAllNonAgentOrCustomWorkspaceSize() { continue; } Map paths = getAgentWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()) { + for(Entry entry : paths.entrySet()) { TopLevelItem item = null; if(owner instanceof TopLevelItem) { item = (TopLevelItem) owner; @@ -371,8 +372,8 @@ public Long getAllNonAgentOrCustomWorkspaceSize() { item = (TopLevelItem) owner.getParent(); } try { - if(!isContainedInWorkspace(item, node, path)) { - size += paths.get(path); + if(!isContainedInWorkspace(item, node, entry.getKey())) { + size += entry.getValue(); } } catch (Exception e) { @@ -412,8 +413,8 @@ public Long getAllWorkspaceSize() { continue; } Map paths = getAgentWorkspaceUsage().get(nodeName); - for(String path: paths.keySet()) { - size += paths.get(path); + for(Entry entry : paths.entrySet()) { + size += entry.getValue(); } } return size; From 72a4dca2cc0943038d9bb55ee2226202bc224194 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 03:02:43 +0000 Subject: [PATCH 068/158] Fix Dead store to local variable --- src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java | 1 - src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java | 1 - src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java | 1 - 3 files changed, 3 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 8bb5e767..83b71787 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -40,7 +40,6 @@ public String getDescription() { } public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); res.sendRedirect(Jenkins.getInstance().getRootUrlFromRequest() + "plugin/disk-usage"); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index c9490abb..d9d388f3 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -477,7 +477,6 @@ public void saveDiskUsage() { } public void loadDiskUsage() { - AbstractProject job = (AbstractProject) owner; diskUsage.load(); // ensure that build was not removed without calling listener - badly removed, or badly saved (without build.xml) for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(false)) { diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 93ef9d24..61b3e110 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -65,7 +65,6 @@ public boolean isBuildsLoaded() { public Set getBuildDiskUsage(boolean needAll) { Set information = new HashSet<>(); - AbstractProject p = (AbstractProject) job; if(needAll && !allBuildsLoaded) { try { loadAllBuilds(); From 26139d6b3e4ec54da3544d7cbe67d0d2c9397e19 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 03:05:07 +0000 Subject: [PATCH 069/158] Fix Redundant nullcheck of value known to be non-null --- src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index d9d388f3..889afd56 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -320,7 +320,7 @@ public void checkWorkspaces(boolean force) { } else { // delete path which does not exists - if(node != null && node.toComputer() != null && node.getChannel() != null) { + if(node.toComputer() != null && node.getChannel() != null) { Map workspaces = diskUsage.slaveWorkspacesUsage.get(nodeName); Iterator pathIterator = workspaces.keySet().iterator(); while(pathIterator.hasNext()) { From 74dad74ec11491d8097b43db4ae5c71e69f362f0 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 03:11:14 +0000 Subject: [PATCH 070/158] Fix Exception is caught when Exception is not thrown --- src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java | 2 +- src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 889afd56..9170c660 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -298,7 +298,7 @@ public void checkWorkspaces(boolean force) { putAgentWorkspace(node, path.getRemote()); } } - catch (Exception e) { + catch (IOException|InterruptedException e) { if (path != null) { LOGGER.warning("Can not check if file " + path.getRemote() + " exists on node " + node.getNodeName()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 80bc6444..a1866b90 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -326,7 +326,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener property.saveDiskUsage(); } } - catch (Exception ex) { + catch (IOException | InterruptedException ex) { listener.getLogger().println("Disk usage plugin fails during calculation disk usage of this build."); Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin fails during build calculation disk space of job " + build.getParent().getDisplayName(), ex); } From 9e630b183a2bf7bdfaa9bc3f9be71af5d8eeef2f Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 09:40:59 +0000 Subject: [PATCH 071/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b41d5e0..2f98ae40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - [Removes deprecated maven property java.level](https://github.com/jenkinsci/disk-usage-plugin/pull/71) - [Order builds by build number for graph show in project page](https://github.com/jenkinsci/disk-usage-plugin/pull/70) - [Removes unused DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/72) +- [Fix spotbugs issues](https://github.com/jenkinsci/disk-usage-plugin/pull/73) ### Release 0.28 (Oct 01, 2015) From 0ef6f4635dbaff188e758fa7332796efd6ad61ec Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 09:45:25 +0000 Subject: [PATCH 072/158] Adds Status category to DiskUsageManagement --- .../hudson/plugins/disk_usage/DiskUsageManagement.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 83b71787..faa86ed4 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -4,6 +4,7 @@ */ package hudson.plugins.disk_usage; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.ManagementLink; import hudson.model.RootAction; @@ -39,6 +40,12 @@ public String getDescription() { return Messages.description(); } + @NonNull + @Override + public Category getCategory() { + return Category.STATUS; + } + public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { res.sendRedirect(Jenkins.getInstance().getRootUrlFromRequest() + "plugin/disk-usage"); } From acfdc22f56d0dc1f516b927d52d116303ba1c290 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 9 Feb 2023 10:03:54 +0000 Subject: [PATCH 073/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f98ae40..6746ec44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [Order builds by build number for graph show in project page](https://github.com/jenkinsci/disk-usage-plugin/pull/70) - [Removes unused DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/72) - [Fix spotbugs issues](https://github.com/jenkinsci/disk-usage-plugin/pull/73) +- [Adds Status category to DiskUsageManagement](https://github.com/jenkinsci/disk-usage-plugin/pull/74) ### Release 0.28 (Oct 01, 2015) From caf1502f98cbce7696420a956cd5c290cf608644 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 10 Feb 2023 20:52:40 +0000 Subject: [PATCH 074/158] Upgrade parent pom.xml to 4.54 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ae633b5e..09485c71 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.53 + 4.54 disk-usage From db2309cd57050f9ee784eab04fb021d3415c1572 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 11 Feb 2023 00:14:35 +0000 Subject: [PATCH 075/158] Upgrade from javax.mail to jakarta.mail --- pom.xml | 6 +++--- .../java/hudson/plugins/disk_usage/DiskUsageUtil.java | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index ae633b5e..e8dee215 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ org.jenkins-ci.plugins mailer - 1.8 + 435.v79ef3972b_5c7 org.jenkins-ci.plugins @@ -45,8 +45,8 @@ io.jenkins.plugins - javax-mail-api - 1.6.2-8 + jakarta-mail-api + 2.0.1-2 diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index a1866b90..ae119f03 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -28,11 +28,11 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.mail.Message.RecipientType; -import javax.mail.MessagingException; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; +import jakarta.mail.Message.RecipientType; +import jakarta.mail.MessagingException; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import jenkins.model.Jenkins; import org.jenkinsci.remoting.RoleChecker; From c903885c8e38320f1c73b9de387991cc955269c6 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 11 Feb 2023 00:37:20 +0000 Subject: [PATCH 076/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6746ec44..8c647d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - [Removes unused DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/72) - [Fix spotbugs issues](https://github.com/jenkinsci/disk-usage-plugin/pull/73) - [Adds Status category to DiskUsageManagement](https://github.com/jenkinsci/disk-usage-plugin/pull/74) +- [Upgrade from javax.mail to jakarta.mail](https://github.com/jenkinsci/disk-usage-plugin/pull/76) ### Release 0.28 (Oct 01, 2015) From f72bc23b0c304f8b453107a42b7cfc2988ac1499 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 2 Mar 2023 01:52:26 +0000 Subject: [PATCH 077/158] Fixes class cast exception with promoted builds plugin Manually cherry picked from commits 1ea3c76902f09a8e7fe27a570aad5db83318bbd3 and 5842185ddfcbfe9cec035dba3ed20a623ef1d60b JENKINS-40728 Invalid class cast in Disk Usage Plugin when ItemGroup is not a TopLevelItem --- pom.xml | 16 ++++++-- .../plugins/disk_usage/DiskUsageProperty.java | 37 ++++++++++++------- .../integration/DiskUsagePropertyTest.java | 19 ++++++++++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index d56f3e6d..560470c1 100644 --- a/pom.xml +++ b/pom.xml @@ -29,9 +29,9 @@ - org.jenkins-ci.plugins - mailer - 435.v79ef3972b_5c7 + org.jenkins-ci.plugins + mailer + 435.v79ef3972b_5c7 org.jenkins-ci.plugins @@ -41,13 +41,21 @@ org.jenkins-ci.plugins junit - 1.0 + 1.20 io.jenkins.plugins jakarta-mail-api 2.0.1-2 + + org.jenkins-ci.plugins + promoted-builds + 3.0 + test + + + diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 9170c660..6136a48b 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -364,12 +364,14 @@ public Long getAllNonAgentOrCustomWorkspaceSize() { } Map paths = getAgentWorkspaceUsage().get(nodeName); for(Entry entry : paths.entrySet()) { - TopLevelItem item = null; + Item item = null; if(owner instanceof TopLevelItem) { - item = (TopLevelItem) owner; + item = owner; } else { - item = (TopLevelItem) owner.getParent(); + if (owner.getParent() instanceof TopLevelItem){ + item = (TopLevelItem) owner.getParent(); + } } try { if(!isContainedInWorkspace(item, node, entry.getKey())) { @@ -384,24 +386,33 @@ public Long getAllNonAgentOrCustomWorkspaceSize() { return size; } - private boolean isContainedInWorkspace(TopLevelItem item, Node node, String path) { + private boolean isContainedInWorkspace(Item item, Node node, String path) { if(node instanceof Slave) { Slave agent = (Slave) node; return path.contains(agent.getRemoteFS()); } else { - if(node instanceof Jenkins) { - FilePath file = Jenkins.getInstance().getWorkspaceFor(item); - return path.contains(file.getRemote()); - } - else { - try { - return path.contains(node.getWorkspaceFor(item).getRemote()); + if (item instanceof TopLevelItem){ + TopLevelItem topLevelItem = (TopLevelItem) item; + if(node instanceof Jenkins) { + FilePath file = Jenkins.getInstance().getWorkspaceFor(topLevelItem); + if (file != null){ + return path.contains(file.getRemote()); + } } - catch (Exception e) { - return false; + else { + try { + final var file = node.getWorkspaceFor(topLevelItem); + if (file != null){ + return path.contains(file.getRemote()); + } + } + catch (Exception e) { + return false; + } } } + return false; } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index ba87c69d..3b9f4815 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -2,6 +2,11 @@ import hudson.Functions; +import hudson.model.FreeStyleBuild; +import hudson.model.Project; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.conditions.SelfPromotionCondition; import hudson.tasks.BatchFile; import java.util.ConcurrentModificationException; import java.util.GregorianCalendar; @@ -51,6 +56,20 @@ public class DiskUsagePropertyTest { @Rule public JenkinsRule j = new JenkinsRule(); + @Issue("JENKINS-40728") + @Test + public void testCalculationWorkspaceForItemInNonTopLeverGroupItem() throws Exception { + final var project = j.createFreeStyleProject("some-project"); + JobPropertyImpl property = new JobPropertyImpl(project); + project.addProperty(property); + PromotionProcess process = property.addProcess("Simple-process"); + process.conditions.add(new SelfPromotionCondition(true)); + process.getBuildSteps().add(new Shell("echo hello > log.log")); + j.buildAndAssertSuccess(project); + DiskUsageProperty p = process.getProperty(DiskUsageProperty.class); + Thread.sleep(1000); + p.getAllNonSlaveOrCustomWorkspaceSize(); + } @Test public void testGetAllDiskUsageWithoutBuilds() throws Exception { From 5d1612bd2eb2b22c8071e6485dd7c46bbe6c69f1 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 2 Mar 2023 02:22:34 +0000 Subject: [PATCH 078/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c647d38..aa6aa21a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - [Fix spotbugs issues](https://github.com/jenkinsci/disk-usage-plugin/pull/73) - [Adds Status category to DiskUsageManagement](https://github.com/jenkinsci/disk-usage-plugin/pull/74) - [Upgrade from javax.mail to jakarta.mail](https://github.com/jenkinsci/disk-usage-plugin/pull/76) +- [Fixes class cast exception with promoted builds plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/77) ### Release 0.28 (Oct 01, 2015) From 689cb00796f9f4ca33245fc64378245d66586747 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 7 Mar 2023 00:26:53 +0000 Subject: [PATCH 079/158] Removes deprecated fields from BuildDiskUsageAction These have been deprecated more than 7 years ago. It should relatively safe to remove this code, enabling new features to be added with more ease. --- .../disk_usage/BuildDiskUsageAction.java | 56 ++-------------- .../plugins/disk_usage/ProjectDiskUsage.java | 62 ++++-------------- .../integration/DiskUsagePropertyTest.java | 14 ---- .../testBackwadrCompatibility1.zip | Bin 38553 -> 0 bytes 4 files changed, 15 insertions(+), 117 deletions(-) delete mode 100644 src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest/testBackwadrCompatibility1.zip diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index f5b04d74..5f3e2f3e 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -1,21 +1,15 @@ package hudson.plugins.disk_usage; -import hudson.FilePath; +import java.io.IOException; +import java.util.Set; + import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.Action; import hudson.model.BuildBadgeAction; import hudson.model.ItemGroup; -import hudson.model.Node; import hudson.model.ProminentProjectAction; import hudson.model.Run; -import hudson.model.TopLevelItem; -import java.io.IOException; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import jenkins.model.RunAction2; -import org.apache.commons.io.FileUtils; import org.kohsuke.stapler.export.ExportedBean; /** @@ -26,11 +20,7 @@ @ExportedBean(defaultVisibility = 1) public class BuildDiskUsageAction implements ProminentProjectAction, BuildBadgeAction, RunAction2 { - @Deprecated - Long buildDiskUsage; AbstractBuild build; - @Deprecated - DiskUsage diskUsage; public BuildDiskUsageAction(AbstractBuild build) { this.build = build; @@ -117,26 +107,6 @@ private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { return buildsDiskUsage; } - public Object readResolve() { - // for keeping backward compatibility - if(diskUsage != null) { - buildDiskUsage = diskUsage.buildUsage; - Node node = build.getBuiltOn(); - if(node != null && diskUsage.wsUsage != null && diskUsage.wsUsage > 0) { - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); - AbstractProject project = build.getProject().getRootProject(); - if(property != null && (project instanceof TopLevelItem)) { - final var workspaceFor = node.getWorkspaceFor((TopLevelItem) project); - if (workspaceFor!=null){ - property.putAgentWorkspaceSize(node, workspaceFor.getRemote(), diskUsage.wsUsage); - } - } - } - diskUsage = null; - } - return this; - } - @Override public void onAttached(Run r) { // no action is needed @@ -149,25 +119,7 @@ public void onLoad(Run r) { if(property == null) { return; } - // backward compatibility - BuildDiskUsageAction action = null; - for(Action a: build.getActions()) { - if(a instanceof BuildDiskUsageAction) { - action = (BuildDiskUsageAction) a; - if(action.buildDiskUsage != null) { - size = action.buildDiskUsage; - } - } - } - if(action != null) { - // remove old action, now it is added by transition action factory - build.getActions().remove(action); - try { - build.save(); - } catch (IOException ex) { - Logger.getLogger(BuildDiskUsageAction.class.getName()).log(Level.SEVERE, null, ex); - } - } + // Transient actions can be created even during deletion of job if(property.getDiskUsageBuildInformation(build.getNumber()) == null && build.getRootDir().exists()) { property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), size), build); diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 61b3e110..752b306a 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -4,17 +4,6 @@ */ package hudson.plugins.disk_usage; -import com.google.common.collect.Maps; -import hudson.BulkChange; -import hudson.XmlFile; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.Action; -import hudson.model.Job; -import hudson.model.Node; -import hudson.model.Run; -import hudson.model.Saveable; -import hudson.model.listeners.SaveableListener; import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -26,6 +15,17 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Level; import java.util.logging.Logger; + +import com.google.common.collect.Maps; +import hudson.BulkChange; +import hudson.XmlFile; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Job; +import hudson.model.Node; +import hudson.model.Run; +import hudson.model.Saveable; +import hudson.model.listeners.SaveableListener; import jenkins.model.Jenkins; import org.apache.commons.io.FileUtils; @@ -149,26 +149,11 @@ public void loadAllBuilds() throws IOException { continue; } AbstractBuild build = (AbstractBuild) run; - BuildDiskUsageAction toRemove = null; - long buildOldDiskUsage = 0L; - // if not present, add - for(Action action: build.getActions()) { - if(action instanceof BuildDiskUsageAction) { - toRemove = (BuildDiskUsageAction) action; - buildOldDiskUsage = toRemove.buildDiskUsage; - } - } - if(toRemove != null) { - build.getActions().remove(toRemove); - } if(build.getWorkspace() != null) { putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); } DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); addBuildInformation(information, build); - if(information.getSize() == 0l) { - information.setSize(buildOldDiskUsage); - } } } allBuildsLoaded = true; @@ -189,31 +174,6 @@ public synchronized void load() { } } - /** - * IT is only for backward compatibility to load old data. It breaks lazy loading. - * Should be used only one times - updating of plugin - * - * @deprecated - * - */ - public void loadOldData() { - buildDiskUsage = new CopyOnWriteArraySet<>(); - List list = job.getBuilds(); - for(Run run: list) { - if(run instanceof AbstractBuild) { - AbstractBuild build = (AbstractBuild) run; - BuildDiskUsageAction usage = run.getAction(BuildDiskUsageAction.class); - DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); - addBuildInformation(information, build); - if(usage != null) { - information.setSize(usage.buildDiskUsage); - run.getAllActions().remove(usage); - } - } - } - save(); - } - public DiskUsageBuildInformation getDiskUsageBuildInformation(int number) { for(DiskUsageBuildInformation information: buildDiskUsage) { if(information.getNumber() == number) { diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 3b9f4815..216ffbaa 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -274,20 +274,6 @@ public void testGetAllNonAgentOrCustomWorkspaceSizeWithMaster() throws Exception assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); } - @Test - @LocalData - public void testBackwadrCompatibility1() throws IOException { - j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableBuildsDiskUsageCalculation(); - j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableJobsDiskUsageCalculation(); - j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableWorkspacesDiskUsageCalculation(); - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - property.getDiskUsage().loadAllBuilds(); - assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); - assertEquals("Size of build 2 should be loaded from previous configuration.", 23932L, property.getDiskUsageOfBuild(2), 0); - } - - @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml") @LocalData diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest/testBackwadrCompatibility1.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest/testBackwadrCompatibility1.zip deleted file mode 100644 index cc3b864f5069e1107c251fa1416a1d2c7d07c3f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38553 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 Date: Tue, 7 Mar 2023 01:18:35 +0000 Subject: [PATCH 080/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa6aa21a..a79cdab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - [Adds Status category to DiskUsageManagement](https://github.com/jenkinsci/disk-usage-plugin/pull/74) - [Upgrade from javax.mail to jakarta.mail](https://github.com/jenkinsci/disk-usage-plugin/pull/76) - [Fixes class cast exception with promoted builds plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/77) +- [Removes deprecated fields from BuildDiskUsageAction](https://github.com/jenkinsci/disk-usage-plugin/pull/79) ### Release 0.28 (Oct 01, 2015) From 3cb7ece5bd9d22348435785117128b53016bc164 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 17 Mar 2023 00:34:24 +0000 Subject: [PATCH 081/158] Fix various warnings warnings identified by Intellij IDEA: - Generics - imports - primitive types - unnecessary casts - missing overrides --- .../disk_usage/BuildDiskUsageAction.java | 40 ++++++----- .../BuildDiskUsageCalculationThread.java | 10 +-- .../DiskUsageBuildActionFactory.java | 2 - .../disk_usage/DiskUsageBuildListener.java | 19 ++--- .../disk_usage/DiskUsageCalculation.java | 7 +- .../disk_usage/DiskUsageItemListener.java | 2 +- .../disk_usage/DiskUsageManagement.java | 3 + .../DiskUsageOvearallGraphGenerator.java | 17 ++--- .../plugins/disk_usage/DiskUsagePlugin.java | 71 +++++++++---------- .../DiskUsageProjectActionFactory.java | 20 ++++-- .../plugins/disk_usage/DiskUsageProperty.java | 22 ++++-- .../plugins/disk_usage/DiskUsageUtil.java | 10 +-- .../DiskUsageWorkspaceListener.java | 3 - .../JobWithoutBuildsDiskUsageCalculation.java | 2 +- .../plugins/disk_usage/ProjectDiskUsage.java | 21 +++--- .../disk_usage/ProjectDiskUsageAction.java | 51 +++++++------ .../DiskUsagePostBuildCalculation.java | 5 +- .../disk_usage/DiskUsageCalculationTest.java | 24 +++---- .../plugins/disk_usage/DiskUsageUtilTest.java | 24 +++---- .../disk_usage/TestDiskUsageCalculation.java | 20 ++---- .../integration/BuildDiskUsageActionTest.java | 36 +++++----- .../BuildDiskUsageCalculationThreadTest.java | 61 ++++++++-------- .../DiskUsageBuildListenerTest.java | 14 ++-- .../integration/DiskUsagePluginTest.java | 34 +++++---- .../integration/DiskUsagePropertyTest.java | 71 ++++++++++--------- .../integration/DiskUsageTestUtil.java | 11 +-- .../integration/DiskUsageUtilTest.java | 34 +++++---- .../JobDiskUsageCalculationThreadTest.java | 22 +++--- .../ProjectDiskUsageActionTest.java | 64 ++++++++--------- .../integration/ProjectDiskUsageTest.java | 17 +++-- ...rkspaceDiskUsageCalculationThreadTest.java | 17 +++-- .../DiskUsagePostBuildCalculationTest.java | 17 ++--- 32 files changed, 397 insertions(+), 374 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java index 5f3e2f3e..35246259 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageAction.java @@ -1,14 +1,13 @@ package hudson.plugins.disk_usage; -import java.io.IOException; -import java.util.Set; - import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildBadgeAction; import hudson.model.ItemGroup; import hudson.model.ProminentProjectAction; import hudson.model.Run; +import java.io.IOException; +import java.util.Set; import jenkins.model.RunAction2; import org.kohsuke.stapler.export.ExportedBean; @@ -20,30 +19,33 @@ @ExportedBean(defaultVisibility = 1) public class BuildDiskUsageAction implements ProminentProjectAction, BuildBadgeAction, RunAction2 { - AbstractBuild build; + AbstractBuild build; - public BuildDiskUsageAction(AbstractBuild build) { + public BuildDiskUsageAction(AbstractBuild build) { this.build = build; } + @Override public String getIconFileName() { return null; } + @Override public String getDisplayName() { return Messages.displayName(); } + @Override public String getUrlName() { return Messages.urlName(); } public void setDiskUsage(Long size) throws IOException { - AbstractProject project = build.getProject(); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + AbstractProject project = build.getProject(); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(project); - property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + property = project.getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); if(information != null) { @@ -59,20 +61,20 @@ public void setDiskUsage(Long size) throws IOException { * @return Disk usage of the build (included child builds) */ public Long getDiskUsage() { - AbstractProject project = build.getProject(); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + AbstractProject project = build.getProject(); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(project); - property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + property = project.getProperty(DiskUsageProperty.class); } return property.getDiskUsageOfBuild(build.getId()); } public Long getAllDiskUsage() { Long buildsDiskUsage = getDiskUsage(); - AbstractProject project = build.getProject(); + AbstractProject project = build.getProject(); if(project instanceof ItemGroup) { - buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) project); + buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) project); } return buildsDiskUsage; } @@ -81,19 +83,19 @@ public String getBuildUsageString() { return DiskUsageUtil.getSizeString(getAllDiskUsage()); } - private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { + private Long getBuildsDiskUsageAllSubItems(ItemGroup group) { Long buildsDiskUsage = 0L; for(Object item: group.getItems()) { if(item instanceof ItemGroup) { - buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) item); + buildsDiskUsage += getBuildsDiskUsageAllSubItems((ItemGroup) item); } else { if(item instanceof AbstractProject) { - AbstractProject project = (AbstractProject) item; - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + AbstractProject project = (AbstractProject) item; + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(project); - property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + property = project.getProperty(DiskUsageProperty.class); } Set informations = property.getDiskUsageOfBuilds(); for(DiskUsageBuildInformation information: informations) { @@ -114,7 +116,7 @@ public void onAttached(Run r) { @Override public void onLoad(Run r) { - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + DiskUsageProperty property = build.getProject().getProperty(DiskUsageProperty.class); long size = 0L; if(property == null) { return; diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index d1fb8805..b5eaba62 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -7,6 +7,7 @@ import hudson.model.AperiodicWork; import hudson.model.Item; import hudson.model.ItemGroup; +import hudson.model.RunMap; import hudson.model.TaskListener; import hudson.scheduler.CronTab; import java.io.IOException; @@ -14,7 +15,6 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; -import java.util.logging.Logger; import jenkins.model.Jenkins; @@ -43,7 +43,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(Object item: items) { if(item instanceof AbstractProject) { - AbstractProject project = (AbstractProject) item; + AbstractProject project = (AbstractProject) item; DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { property = new DiskUsageProperty(); @@ -51,8 +51,9 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } ProjectDiskUsage diskUsage = property.getProjectDiskUsage(); for(DiskUsageBuildInformation information: diskUsage.getBuildDiskUsage(true)) { - Map loadedBuilds = project._getRuns().getLoadedBuilds(); - AbstractBuild build = loadedBuilds.get(information.getNumber()); + final RunMap runMap = project._getRuns(); + Map loadedBuilds = runMap.getLoadedBuilds(); + AbstractBuild build = (AbstractBuild) loadedBuilds.get(information.getNumber()); // do not calculat builds in progress if(build != null && build.isBuilding()) { continue; @@ -81,6 +82,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } } + @Override public CronTab getCronTab() throws ANTLRException { String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); return new CronTab(cron); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java index cebd7f61..347b77d2 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildActionFactory.java @@ -7,8 +7,6 @@ import hudson.Extension; import hudson.model.AbstractBuild; import hudson.model.Action; -import hudson.model.Run; -import hudson.model.TransientBuildActionFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java index ec70d3eb..2edf5452 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildListener.java @@ -1,5 +1,6 @@ package hudson.plugins.disk_usage; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.AbstractBuild; import hudson.model.TaskListener; @@ -12,10 +13,10 @@ * @author Lucie Votypkova */ @Extension -public class DiskUsageBuildListener extends RunListener { +public class DiskUsageBuildListener extends RunListener> { @Override - public void onCompleted(AbstractBuild build, TaskListener listener) { + public void onCompleted(AbstractBuild build, @NonNull TaskListener listener) { Long diskUsage = build.getAction(BuildDiskUsageAction.class).getDiskUsage(); if(build.getProject().getPublishersList().get(DiskUsagePostBuildCalculation.class) == null || diskUsage == 0) { DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); @@ -26,11 +27,11 @@ public void onCompleted(AbstractBuild build, TaskListener listener) { } @Override - public void onDeleted(AbstractBuild build) { - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + public void onDeleted(AbstractBuild build) { + DiskUsageProperty property = build.getProject().getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + property = build.getProject().getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); if(information != null) { @@ -40,15 +41,15 @@ public void onDeleted(AbstractBuild build) { } @Override - public void onStarted(AbstractBuild build, TaskListener listener) { - DiskUsageProperty property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + public void onStarted(AbstractBuild build, TaskListener listener) { + DiskUsageProperty property = build.getProject().getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(build.getProject()); - property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); + property = build.getProject().getProperty(DiskUsageProperty.class); } DiskUsageBuildInformation information = property.getDiskUsageBuildInformation(build.getId()); if(information == null) { - property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), 0l), build); + property.getDiskUsage().addBuildInformation(new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.getNumber(), 0L), build); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index ca56980b..762db054 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -7,7 +7,6 @@ import antlr.ANTLRException; import hudson.model.AsyncAperiodicWork; import hudson.scheduler.CronTab; -import hudson.triggers.Trigger; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.concurrent.ScheduledExecutorService; @@ -58,11 +57,9 @@ public String getThreadName() { public long scheduledLastInstanceExecutionTime() { try { - CronTab tab = null; if(getLastTask() == null || getLastTask().isCancelled()) { // not scheduled - return 0l; + return 0L; } - tab = getLastTask().getCronTab(); long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); if(time < new GregorianCalendar().getTimeInMillis()) { return 0; @@ -115,7 +112,7 @@ public long getRecurrencePeriod() { Calendar nextExecution = tab.ceil(now.getTimeInMillis()); long period = nextExecution.getTimeInMillis() - now.getTimeInMillis(); if(nextExecution.getTimeInMillis() - now.getTimeInMillis() <= 60000) { - period = period + 60000l; // add one minute to not shedule it during one minute one than once + period = period + 60_000L; // add one minute to not shedule it during one minute one than once } return period; } catch (Exception ex) { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java index 2784187f..020b06db 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java @@ -21,7 +21,7 @@ public class DiskUsageItemListener extends ItemListener { @Override public void onDeleted(Item item) { if(item instanceof AbstractProject) { - DiskUsageProjectActionFactory.DESCRIPTOR.onDeleteJob((AbstractProject) item); + DiskUsageProjectActionFactory.DESCRIPTOR.onDeleteJob((AbstractProject) item); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index faa86ed4..9fc659e7 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -23,14 +23,17 @@ public class DiskUsageManagement extends ManagementLink implements RootAction { public final String[] COLUMNS = new String[]{"Project name", "Builds", "Workspace", "JobDirectory (without builds)"}; + @Override public String getIconFileName() { return "/plugin/disk-usage/icons/disk-usage.svg"; } + @Override public String getDisplayName() { return Messages.displayName(); } + @Override public String getUrlName() { return "disk-usage"; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 8cda782f..47d0cde3 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -9,6 +9,7 @@ import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Objects; import jenkins.model.Jenkins; /** @@ -35,7 +36,7 @@ protected void doRun() throws Exception { } public static class DiskUsageRecord extends DiskUsage { - private static SimpleDateFormat sdf = new SimpleDateFormat("d/M"); + private static final SimpleDateFormat sdf = new SimpleDateFormat("d/M"); Date date; private Long jobsWithoutBuildsUsage = 0L; private Long allSpace = 0L; @@ -62,10 +63,7 @@ public Long getNonSlaveWorkspacesUsage() { } public Long getNonAgentWorkspacesUsage() { - if(diskUsageNonAgentWorkspaces == null) { - return 0l; - } - return diskUsageNonAgentWorkspaces; + return Objects.requireNonNullElse(diskUsageNonAgentWorkspaces, 0L); } @Deprecated(forRemoval = true) @@ -81,10 +79,7 @@ public Long getAgentWorkspacesUsage() { } public Long getBuildsDiskUsage() { - if(buildUsage == null) { - return 0l; - } - return buildUsage; + return Objects.requireNonNullElse(buildUsage, 0L); } public Long getJobsDiskUsage() { @@ -96,14 +91,14 @@ public Long getJobsDiskUsage() { public Long getAllSpace() { if(allSpace == null) { - return 0l; + return 0L; } return allSpace; } public Long getWorkspacesDiskUsage() { if(wsUsage == null) { - return 0l; + return 0L; } return wsUsage; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 1789235e..175582a9 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -2,9 +2,11 @@ import hudson.Extension; import hudson.Plugin; -import hudson.model.*; +import hudson.model.AbstractProject; +import hudson.model.AperiodicWork; +import hudson.model.Item; +import hudson.model.Job; import hudson.util.Graph; - import java.io.File; import java.io.IOException; import java.util.Collections; @@ -18,10 +20,9 @@ import org.kohsuke.stapler.StaplerResponse; /** - * Entry point of the the plugin. + * Entry point of the plugin. * * @author dvrzalik - * @plugin */ @Extension public class DiskUsagePlugin extends Plugin { @@ -36,14 +37,14 @@ public DiskUsagePlugin() { } public void refreshGlobalInformation() throws IOException { - diskUsageBuilds = 0l; - diskUsageWorkspaces = 0l; - diskUsageJobsWithoutBuilds = 0l; - diskUsageLockedBuilds = 0l; - diskUsageNonAgentWorkspaces = 0l; + diskUsageBuilds = 0L; + diskUsageWorkspaces = 0L; + diskUsageJobsWithoutBuilds = 0L; + diskUsageLockedBuilds = 0L; + diskUsageNonAgentWorkspaces = 0L; for(Item item: Jenkins.getInstance().getItems()) { if(item instanceof AbstractProject) { - AbstractProject project = (AbstractProject) item; + AbstractProject project = (AbstractProject) item; ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); diskUsageBuilds += action.getBuildsDiskUsage().get("all"); diskUsageWorkspaces += action.getAllDiskUsageWorkspace(); @@ -147,7 +148,7 @@ public WorkspaceDiskUsageCalculationThread getWorkspaceDiskUsageThread() { /** * @return DiskUsage for given project (shortcut for the view). Never null. */ - public ProjectDiskUsageAction getDiskUsage(Job project) { + public ProjectDiskUsageAction getDiskUsage(Job project) { return project.getAction(ProjectDiskUsageAction.class); } @@ -158,28 +159,26 @@ public String getDiskUsageInString(Long size) { /** * @return Project list sorted by occupied disk space */ - public List getProjectList() throws IOException { + public List getProjectList() throws IOException { refreshGlobalInformation(); - Comparator comparator = new Comparator() { - - public int compare(AbstractProject o1, AbstractProject o2) { + Comparator comparator = (o1, o2) -> { - ProjectDiskUsageAction dua1 = getDiskUsage(o1); - ProjectDiskUsageAction dua2 = getDiskUsage(o2); - long result = dua2.getJobRootDirDiskUsage() + dua2.getAllDiskUsageWorkspace() - dua1.getJobRootDirDiskUsage() - dua1.getAllDiskUsageWorkspace(); + ProjectDiskUsageAction dua1 = getDiskUsage(o1); + ProjectDiskUsageAction dua2 = getDiskUsage(o2); + long result = dua2.getJobRootDirDiskUsage() + dua2.getAllDiskUsageWorkspace() - dua1.getJobRootDirDiskUsage() - + dua1.getAllDiskUsageWorkspace(); - if(result > 0) { - return 1; - } - if(result < 0) { - return -1; - } - return 0; + if (result > 0) { + return 1; + } + if (result < 0) { + return -1; } + return 0; }; List projectList = Jenkins.getInstance().getAllItems(AbstractProject.class); - Collections.sort(projectList, comparator); + projectList.sort(comparator); return projectList; } @@ -226,22 +225,22 @@ public Graph getOverallGraph() { for(DiskUsageOvearallGraphGenerator.DiskUsageRecord usage: record) { Date label = usage.getDate(); if(getConfiguration().getShowFreeSpaceForJobDirectory()) { - dataset.addValue(((Long) usage.getAllSpace()) / base, "space for jobs directory", label); + dataset.addValue(usage.getAllSpace() / base, "space for jobs directory", label); } - dataset.addValue(((Long) usage.getJobsDiskUsage()) / base, "all jobs", label); - dataset.addValue(((Long) usage.getBuildsDiskUsage()) / base, "all builds", label); - datasetW.addValue(((Long) usage.getAgentWorkspacesUsage()) / baseWorkspace, "agent workspaces", label); - datasetW.addValue(((Long) usage.getNonAgentWorkspacesUsage()) / baseWorkspace, "non agent workspaces", label); + dataset.addValue(usage.getJobsDiskUsage() / base, "all jobs", label); + dataset.addValue(usage.getBuildsDiskUsage() / base, "all builds", label); + datasetW.addValue(usage.getAgentWorkspacesUsage() / baseWorkspace, "agent workspaces", label); + datasetW.addValue(usage.getNonAgentWorkspacesUsage() / baseWorkspace, "non agent workspaces", label); } // add current state if(getConfiguration().getShowFreeSpaceForJobDirectory()) { - dataset.addValue(((Long) jobsDir.getTotalSpace()) / base, "space for jobs directory", "current"); + dataset.addValue(jobsDir.getTotalSpace() / base, "space for jobs directory", "current"); } - dataset.addValue(((Long) getCashedGlobalJobsDiskUsage()) / base, "all jobs", "current"); - dataset.addValue(((Long) getCashedGlobalBuildsDiskUsage()) / base, "all builds", "current"); - datasetW.addValue(((Long) getCashedAgentDiskUsageWorkspace()) / baseWorkspace, "agent workspaces", "current"); - datasetW.addValue(((Long) getCashedNonAgentDiskUsageWorkspace()) / baseWorkspace, "non agent workspaces", "current"); + dataset.addValue(getCashedGlobalJobsDiskUsage() / base, "all jobs", "current"); + dataset.addValue(getCashedGlobalBuildsDiskUsage() / base, "all builds", "current"); + datasetW.addValue(getCashedAgentDiskUsageWorkspace() / baseWorkspace, "agent workspaces", "current"); + datasetW.addValue(getCashedNonAgentDiskUsageWorkspace() / baseWorkspace, "non agent workspaces", "current"); return new DiskUsageGraph(dataset, unit, datasetW, unitWorkspace); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index dbfe9539..2764b7fd 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -1,7 +1,13 @@ package hudson.plugins.disk_usage; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import hudson.model.*; +import hudson.model.AbstractProject; +import hudson.model.Action; +import hudson.model.AperiodicWork; +import hudson.model.Describable; +import hudson.model.Descriptor; +import hudson.model.TransientProjectActionFactory; import hudson.security.Permission; import java.util.ArrayList; import java.util.Collection; @@ -30,6 +36,7 @@ public Collection createFor(AbstractProject job) { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); + @Override public Descriptor getDescriptor() { return DESCRIPTOR; } @@ -278,6 +285,7 @@ public String getValue(String size) { } + @NonNull @Override public String getDisplayName() { return Messages.displayName(); @@ -285,7 +293,7 @@ public String getDisplayName() { @Override - public DiskUsageProjectActionFactory newInstance(StaplerRequest req, JSONObject formData) { + public DiskUsageProjectActionFactory newInstance(StaplerRequest req, @NonNull JSONObject formData) { return new DiskUsageProjectActionFactory(); } @@ -335,14 +343,12 @@ public void onRenameJob(String oldName, String newName) { } } - public void onDeleteJob(AbstractProject project) { + public void onDeleteJob(AbstractProject project) { String name = project.getName(); - if(excludedJobs.contains(name)) { - excludedJobs.remove(name); - } + excludedJobs.remove(name); } - public boolean isExcluded(AbstractProject project) { + public boolean isExcluded(AbstractProject project) { return excludedJobs.contains(project.getName()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 6136a48b..c006ac65 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -1,27 +1,37 @@ package hudson.plugins.disk_usage; - -import hudson.model.*; import hudson.Extension; import hudson.FilePath; import hudson.init.InitMilestone; import hudson.init.Initializer; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Action; +import hudson.model.Descriptor; +import hudson.model.Hudson; +import hudson.model.Item; +import hudson.model.ItemGroup; +import hudson.model.Job; +import hudson.model.JobProperty; +import hudson.model.JobPropertyDescriptor; +import hudson.model.Node; +import hudson.model.Slave; +import hudson.model.TopLevelItem; import java.io.File; import java.io.IOException; -import java.util.Map.Entry; -import net.sf.json.JSONObject; -import org.kohsuke.stapler.StaplerRequest; - import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; /** * This Property sets DiskUsage action. diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index ae119f03..769a6bcf 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -14,6 +14,11 @@ import hudson.model.TaskListener; import hudson.remoting.Callable; import hudson.tasks.Mailer; +import jakarta.mail.Message.RecipientType; +import jakarta.mail.MessagingException; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -28,11 +33,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import jakarta.mail.Message.RecipientType; -import jakarta.mail.MessagingException; -import jakarta.mail.Transport; -import jakarta.mail.internet.InternetAddress; -import jakarta.mail.internet.MimeMessage; import jenkins.model.Jenkins; import org.jenkinsci.remoting.RoleChecker; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java index a2d18282..fad35922 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageWorkspaceListener.java @@ -7,9 +7,6 @@ import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.WorkspaceListener; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; /** * diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index a7fd21e5..6224025f 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -44,7 +44,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept for(Object item: items) { if(item instanceof AbstractProject) { - AbstractProject project = (AbstractProject) item; + AbstractProject project = (AbstractProject) item; // do not count building project if(project.isBuilding()) { continue; diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 752b306a..1333e76f 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -4,6 +4,16 @@ */ package hudson.plugins.disk_usage; +import com.google.common.collect.Maps; +import hudson.BulkChange; +import hudson.XmlFile; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Job; +import hudson.model.Node; +import hudson.model.Run; +import hudson.model.Saveable; +import hudson.model.listeners.SaveableListener; import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -15,17 +25,6 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Level; import java.util.logging.Logger; - -import com.google.common.collect.Maps; -import hudson.BulkChange; -import hudson.XmlFile; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.Job; -import hudson.model.Node; -import hudson.model.Run; -import hudson.model.Saveable; -import hudson.model.listeners.SaveableListener; import jenkins.model.Jenkins; import org.apache.commons.io.FileUtils; diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 9c959a03..a735c9b2 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -2,10 +2,9 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.Run; import hudson.model.ItemGroup; import hudson.model.ProminentProjectAction; -import hudson.util.ChartUtil.NumberOnlyBuildLabel; +import hudson.model.Run; import hudson.util.Graph; import java.io.IOException; import java.util.ArrayList; @@ -15,11 +14,9 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import java.util.stream.Stream; import jenkins.model.Jenkins; import org.jfree.data.category.DefaultCategoryDataset; import org.kohsuke.stapler.export.ExportedBean; @@ -32,20 +29,23 @@ @ExportedBean(defaultVisibility = 1) public class ProjectDiskUsageAction implements ProminentProjectAction { - AbstractProject project; + AbstractProject, ? extends AbstractBuild> project; - public ProjectDiskUsageAction(AbstractProject project) { + public ProjectDiskUsageAction(AbstractProject, ? extends AbstractBuild> project) { this.project = project; } + @Override public String getIconFileName() { return null; } + @Override public String getDisplayName() { return Messages.displayName(); } + @Override public String getUrlName() { return Messages.urlName(); } @@ -80,11 +80,11 @@ public Long getAllCustomOrNonAgentWorkspaces() { diskUsage += property.getAllNonAgentOrCustomWorkspaceSize(); } if(project instanceof ItemGroup) { - ItemGroup group = (ItemGroup) project; + ItemGroup group = (ItemGroup) project; for(Object i:group.getItems()) { if(i instanceof AbstractProject) { - AbstractProject p = (AbstractProject) i; - DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); + AbstractProject p = (AbstractProject) i; + DiskUsageProperty prop = p.getProperty(DiskUsageProperty.class); if(prop != null) { diskUsage += prop.getAllNonAgentOrCustomWorkspaceSize(); } @@ -106,11 +106,11 @@ public Long getAllDiskUsageWorkspace() { diskUsage += property.getAllWorkspaceSize(); } if(project instanceof ItemGroup) { - ItemGroup group = (ItemGroup) project; + ItemGroup group = (ItemGroup) project; for(Object i:group.getItems()) { if(i instanceof AbstractProject) { - AbstractProject p = (AbstractProject) i; - DiskUsageProperty prop = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); + AbstractProject p = (AbstractProject) i; + DiskUsageProperty prop = p.getProperty(DiskUsageProperty.class); if(prop != null) { diskUsage += prop.getAllWorkspaceSize(); } @@ -152,22 +152,22 @@ public Long getJobRootDirDiskUsage() { } } - private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date older, Date yonger) throws IOException { + private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date older, Date yonger) throws IOException { Map diskUsage = new TreeMap<>(); Long buildsDiskUsage = 0L; Long locked = 0L; Long notLoaded = 0L; for(Object item: group.getItems()) { if(item instanceof ItemGroup) { - ItemGroup subGroup = (ItemGroup) item; + ItemGroup subGroup = (ItemGroup) item; buildsDiskUsage += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("all"); locked += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("locked"); notLoaded += getBuildsDiskUsageAllSubItems(subGroup, older, yonger).get("notLoaded"); } else { if(group instanceof AbstractProject) { - AbstractProject p = (AbstractProject) item; - DiskUsageProperty property = (DiskUsageProperty) p.getProperty(DiskUsageProperty.class); + AbstractProject p = (AbstractProject) item; + DiskUsageProperty property = p.getProperty(DiskUsageProperty.class); if(property == null) { DiskUsageUtil.addProperty(project); property = project.getProperty(DiskUsageProperty.class); @@ -184,8 +184,8 @@ private Map getBuildsDiskUsageAllSubItems(ItemGroup group, Date ol Long size = information.getSize(); buildsDiskUsage += size; Collection loadedBuilds = (Collection) p._getRuns().getLoadedBuilds().values(); - AbstractBuild build = null; - for(AbstractBuild b: loadedBuilds) { + AbstractBuild build = null; + for(AbstractBuild b: loadedBuilds) { if(b.getId().equals(information.getId())) { build = b; } @@ -232,7 +232,7 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx Long notLoaded = 0L; if(project instanceof ItemGroup) { - ItemGroup group = (ItemGroup) project; + ItemGroup group = (ItemGroup) project; Map sizes = getBuildsDiskUsageAllSubItems(group, older, yonger); buildsDiskUsage += sizes.get("all"); locked += sizes.get("locked"); @@ -249,9 +249,9 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx } Long size = information.getSize(); buildsDiskUsage += size; - Collection loadedBuilds = (Collection) project._getRuns().getLoadedBuilds().values(); - AbstractBuild build = null; - for(AbstractBuild b: loadedBuilds) { + Collection> loadedBuilds = (Collection>) project._getRuns().getLoadedBuilds().values(); + AbstractBuild build = null; + for(AbstractBuild b: loadedBuilds) { if(b.getId().equals(information.getId())) { build = b; } @@ -273,7 +273,7 @@ public Map getBuildsDiskUsage(Date older, Date yonger) throws IOEx } public BuildDiskUsageAction getLastBuildAction() { - Run run = project.getLastBuild(); + Run run = project.getLastBuild(); if(run != null) { return run.getAction(BuildDiskUsageAction.class); } @@ -301,8 +301,7 @@ public Graph getGraph() throws IOException { long maxValueWorkspace = 0; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); maxValueWorkspace = Math.max(getAllCustomOrNonAgentWorkspaces(), getAllAgentWorkspaces()); - Long jobRootDirDiskUsage = getJobRootDirDiskUsage(); - maxValue = jobRootDirDiskUsage; + maxValue = getJobRootDirDiskUsage(); // First iteration just to get scale of the y-axis final var builds = property.getDiskUsageOfBuilds() .stream() @@ -325,7 +324,7 @@ public Graph getGraph() throws IOException { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset dataset2 = new DefaultCategoryDataset(); for (Object[] usage : usages) { - String label = "#" + (Integer) usage[0]; + String label = "#" + usage[0]; dataset.addValue(((Long) usage[1]) / base, Messages.DiskUsage_Graph_JobDirectory(), label); dataset.addValue(((Long) usage[2]) / base, Messages.DiskUsage_Graph_BuildDirectory(), label); dataset2.addValue(((Long) usage[3]) / workspaceBase, Messages.DiskUsage_Graph_AgentWorkspaces(), label); diff --git a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java index a9b82f86..7c1ab7c0 100644 --- a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java @@ -4,6 +4,7 @@ */ package hudson.plugins.disk_usage.project; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.Launcher; import hudson.model.AbstractProject; @@ -42,12 +43,14 @@ public BuildStepMonitor getRequiredMonitorService() { @Extension public static class DescriptorImpl extends BuildStepDescriptor { + @NonNull + @Override public String getDisplayName() { return "Calcualete disk usage of build"; } @Override - public DiskUsagePostBuildCalculation newInstance(StaplerRequest req, JSONObject formData) throws FormException { + public DiskUsagePostBuildCalculation newInstance(StaplerRequest req, @NonNull JSONObject formData) throws FormException { return new DiskUsagePostBuildCalculation(); } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index afdd3e07..cf351f4e 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -33,12 +33,12 @@ public void testScheduledExecutionTime() throws Exception { calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation - TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *", false); + TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *"); if(calculation.getLastTask() != null) { // should not be any, but if cancel; calculation.getLastTask().cancel(); } - Long expectedNextExecution = calendar.getTimeInMillis(); + long expectedNextExecution = calendar.getTimeInMillis(); assertEquals("Scheduled time of disk usage calculation should 0, because calculation is not scheduled", 0, calculation.scheduledLastInstanceExecutionTime(), 60000); Timer.get().schedule(calculation.getNewInstance(), calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); assertEquals("Scheduled time of disk usage calculation should be in 10 minutes", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); @@ -62,9 +62,9 @@ public void testGetRecurrencePeriod() { minute = minute + 2; calendar.add(Calendar.MINUTE, 2); minute = calendar.get(Calendar.MINUTE); - TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *", false); - Long period = calculation.getRecurrencePeriod(); - Long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); + TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *"); + long period = calculation.getRecurrencePeriod(); + long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculation should be executed accurately in 2 minutes", expectedPeriod, period, 60000); // for hours @@ -73,7 +73,7 @@ public void testGetRecurrencePeriod() { calendar.add(Calendar.HOUR_OF_DAY, 2); // add 2 hours hour = calendar.get(Calendar.HOUR_OF_DAY); calendar.set(Calendar.MINUTE, 0); - calculation = new TestDiskUsageCalculation("0 " + hour + " * * *", false); + calculation = new TestDiskUsageCalculation("0 " + hour + " * * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 hours.", expectedPeriod, period, 60000); @@ -82,7 +82,7 @@ public void testGetRecurrencePeriod() { calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, 2); int day = calendar.get(Calendar.DAY_OF_MONTH); - calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *", false); + calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); assertEquals("Disk usage calculaion should be executed accurately in 2 days.", expectedPeriod, period, 60000); @@ -91,7 +91,7 @@ public void testGetRecurrencePeriod() { calendar = new GregorianCalendar(); calendar.add(Calendar.MONTH, 2); int month = calendar.get(Calendar.MONTH) + 1; // months are indexed from 0 - calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + month + " *", false); + calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + month + " *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); @@ -101,7 +101,7 @@ public void testGetRecurrencePeriod() { calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_WEEK, 2); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1; - calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + (calendar.get(Calendar.MONTH) + 1) + " " + dayOfWeek, false); + calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + calendar.get(Calendar.DAY_OF_MONTH) + " " + (calendar.get(Calendar.MONTH) + 1) + " " + dayOfWeek); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); @@ -112,7 +112,7 @@ public void testGetRecurrencePeriod() { /** * Depends on test testScheduledExecutionTime() - if testReshedule fails this test probably will fail too. - * + *

    * see @testScheduledExecutionTime() */ @Test @@ -121,7 +121,7 @@ public void testReschedule() throws Exception { calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); // attribut currentTask should have value calculation - TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *", true).getNewInstance(); + TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *").getNewInstance(); Timer.get().schedule(calculation, calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); // schedule it; calendar.add(Calendar.MINUTE, 10); minute = calendar.get(Calendar.MINUTE); @@ -136,7 +136,7 @@ public void testReschedule() throws Exception { public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { // attribut currentTask should have value calculation List scheduledInstances = new ArrayList<>(); - TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *", false).getNewInstance(); + TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *").getNewInstance(); TestDiskUsageCalculation.startLoadInstancesHistory(scheduledInstances); final var thread = new Thread(() -> { diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java index 4033bf8e..e6030585 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java @@ -12,19 +12,19 @@ public class DiskUsageUtilTest { @Test public void testGetSizeInBytes() { String sizeInString = "57 B"; - Long size = 57L; - Assert.assertEquals("Byte representation of size 57 B is wrong.", 57, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + long size = 57L; + Assert.assertEquals("Byte representation of size 57 B is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "5 KB"; - size = 1024l * 5; + size = 1024L * 5; Assert.assertEquals("Byte representation of size 5 KB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "9 MB"; - size = 1024l * 1024 * 9; + size = 1024L * 1024 * 9; Assert.assertEquals("Byte representation of size 9 MB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "1 GB"; - size = 1024l * 1024 * 1024; + size = 1024L * 1024 * 1024; Assert.assertEquals("Byte representation of size 1 GB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "2 TB"; - size = 1024l * 1024 * 1024 * 1024 * 2; + size = 1024L * 1024 * 1024 * 1024 * 2; Assert.assertEquals("Byte representation of size 2 TB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); sizeInString = "-"; Assert.assertEquals("Byte representation of size - is wrong.", 0, DiskUsageUtil.getSizeInBytes(sizeInString), 0); @@ -33,22 +33,22 @@ public void testGetSizeInBytes() { @Test public void testGetSizeInString() { String sizeInString = "57 B"; - Long size = 57L; + long size = 57L; Assert.assertEquals("String representation of size 57 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "5 KB"; - size = 1024l * 5; + size = 1024L * 5; Assert.assertEquals("String representation of size 5 KB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "9 MB"; - size = 1024l * 1024 * 9; + size = 1024L * 1024 * 9; Assert.assertEquals("String representation of size 9 MB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "1 GB"; - size = 1024l * 1024 * 1024; + size = 1024L * 1024 * 1024; Assert.assertEquals("String representation of size 1 GB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "2 TB"; - size = 1024l * 1024 * 1024 * 1024 * 2; + size = 1024L * 1024 * 1024 * 1024 * 2; Assert.assertEquals("String representation of size 2 TB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); sizeInString = "-"; - size = 0l; + size = 0L; Assert.assertEquals("String representation of size 0 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); } diff --git a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java index 20114130..1abcf8ef 100644 --- a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java +++ b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java @@ -4,9 +4,7 @@ import hudson.model.AperiodicWork; import hudson.model.TaskListener; import hudson.scheduler.CronTab; -import hudson.triggers.Trigger; import java.util.List; -import jenkins.util.Timer; /* * To change this template, choose Tools | Templates @@ -23,17 +21,14 @@ public class TestDiskUsageCalculation extends BuildDiskUsageCalculationThread { public boolean executing; - private boolean sleep; - private static List instancesHistory; - private static int maxInstances = 10; + private final static int maxInstances = 10; private static TestDiskUsageCalculation currentInstance; - public TestDiskUsageCalculation(String cron, boolean sleep) { + public TestDiskUsageCalculation(String cron) { this.cron = cron; - this.sleep = true; } public void setCron(String cron) { @@ -56,19 +51,16 @@ public static void stopLoadInstancesHistory() { @Override public void execute(TaskListener listener) { executing = true; - if(sleep) { - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - executing = false; - } + try { + Thread.sleep(10000); + } catch (InterruptedException ignored) { } executing = false; } @Override public AperiodicWork getNewInstance() { - TestDiskUsageCalculation c = new TestDiskUsageCalculation(cron, sleep); + TestDiskUsageCalculation c = new TestDiskUsageCalculation(cron); if(instancesHistory != null) { if(maxInstances <= instancesHistory.size()) { instancesHistory.get(0).cancel(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index eff4b9ab..2e42d2df 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -1,19 +1,19 @@ package hudson.plugins.disk_usage.integration; -import hudson.model.Action; -import java.util.List; -import hudson.plugins.disk_usage.BuildDiskUsageAction; -import org.junit.Test; -import hudson.matrix.MatrixConfiguration; -import hudson.matrix.MatrixBuild; -import hudson.model.AbstractBuild; +import static org.junit.Assert.assertEquals; + import hudson.matrix.AxisList; -import hudson.matrix.TextAxis; +import hudson.matrix.MatrixBuild; +import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; +import hudson.matrix.TextAxis; +import hudson.model.AbstractBuild; +import hudson.model.Action; import hudson.model.FreeStyleProject; -import org.jvnet.hudson.test.JenkinsRule; +import hudson.plugins.disk_usage.BuildDiskUsageAction; import org.junit.Rule; -import static org.junit.Assert.*; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; /** * @@ -35,7 +35,7 @@ public void testGetAllDiskUsage() throws Exception { list.add(axis2); matrixProject.setAxes(list); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); @@ -52,10 +52,10 @@ public void testGetAllDiskUsage() throws Exception { Long matrixBuild1TotalSize = sizeOfMatrixBuild1; Long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()) { - AbstractBuild configurationBuild = c.getBuildByNumber(1); + AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count * size1; - AbstractBuild configurationBuild2 = c.getBuildByNumber(2); + AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count * size2; count++; @@ -81,7 +81,7 @@ public void getBuildUsageStringMatrixProject() throws Exception { Long kiloBytes = 2048L; int count = 0; for(MatrixConfiguration c: matrixProject.getItems()) { - AbstractBuild configurationBuild = c.getBuildByNumber(1); + AbstractBuild configurationBuild = c.getBuildByNumber(1); for(Action action: configurationBuild.getAllActions()) { if(action instanceof BuildDiskUsageAction) { BuildDiskUsageAction a = (BuildDiskUsageAction) action; @@ -107,11 +107,11 @@ public void getBuildUsageStringMatrixProject() throws Exception { public void getBuildUsageStringFreeStyleProject() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); Long bytes = 100L; - Long kiloBytes = 2048L; - Long megaBytes = kiloBytes * 1024; - Long gygaBytes = megaBytes * 1024; + long kiloBytes = 2048L; + long megaBytes = kiloBytes * 1024; + long gygaBytes = megaBytes * 1024; Long teraBytes = gygaBytes * 1024; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(bytes); assertEquals("String representation of build disk usage is wrong which has 100 B is wrong.", "100 B", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index c318d905..e0f9f4d1 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -1,22 +1,21 @@ package hudson.plugins.disk_usage.integration; -import hudson.XmlFile; -import hudson.model.AbstractProject; -import hudson.plugins.disk_usage.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; -import java.util.TreeMap; -import java.util.Map; import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; import hudson.model.AperiodicWork; import hudson.model.FreeStyleBuild; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.jvnet.hudson.test.recipes.LocalData; import hudson.model.FreeStyleProject; import hudson.model.ItemGroup; import hudson.model.TaskListener; import hudson.model.listeners.RunListener; +import hudson.plugins.disk_usage.BuildDiskUsageCalculationThread; +import hudson.plugins.disk_usage.DiskUsageBuildListener; +import hudson.plugins.disk_usage.DiskUsageProjectActionFactory; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -25,10 +24,14 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; -import static org.junit.Assert.*; +import org.jvnet.hudson.test.recipes.LocalData; /** * @@ -65,7 +68,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long lenght = 0L; + long lenght = 0L; for(File file: files) { lenght += file.length(); } @@ -76,17 +79,17 @@ private Long getSize(List files) { @LocalData public void testExecute() throws IOException, InterruptedException { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject1 = new TreeMap<>(); - Map buildSizesProject2 = new TreeMap<>(); + Map, Long> buildSizesProject1 = new TreeMap<>(); + Map, Long> buildSizesProject2 = new TreeMap<>(); FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); - for(AbstractBuild build: project.getBuilds()) { + for(AbstractBuild build: project.getBuilds()) { File file = new File(build.getRootDir(), "fileList"); buildSizesProject1.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } - for(AbstractBuild build: project2.getBuilds()) { + for(AbstractBuild build: project2.getBuilds()) { File file = new File(build.getRootDir(), "fileList"); buildSizesProject2.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } @@ -96,11 +99,11 @@ public void testExecute() throws IOException, InterruptedException { } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - for(AbstractBuild build: buildSizesProject1.keySet()) { + for(AbstractBuild build: buildSizesProject1.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject1.get(build), size, 0); } - for(AbstractBuild build: buildSizesProject2.keySet()) { + for(AbstractBuild build: buildSizesProject2.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), size, 0); } @@ -111,20 +114,20 @@ public void testExecute() throws IOException, InterruptedException { @LocalData public void testExecuteMatrixProject() throws IOException, InterruptedException { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); - Map buildSizesProject2 = new TreeMap<>(); + Map, Long> buildSizesProject2 = new TreeMap<>(); Map matrixConfigurationBuildsSize = new TreeMap<>(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); FreeStyleProject project2 = (FreeStyleProject) j.jenkins.getItem("project2"); - AbstractBuild matrixBuild = project.getBuildByNumber(1); - Long matrixProjectBuildSize = getSize(readFileList(new File(matrixBuild.getRootDir(), "fileList"))) + matrixBuild.getRootDir().length(); - for(AbstractBuild build: project2.getBuilds()) { + AbstractBuild matrixBuild = project.getBuildByNumber(1); + long matrixProjectBuildSize = getSize(readFileList(new File(matrixBuild.getRootDir(), "fileList"))) + matrixBuild.getRootDir().length(); + for(AbstractBuild build: project2.getBuilds()) { File file = new File(build.getRootDir(), "fileList"); buildSizesProject2.put(build, getSize(readFileList(file)) + build.getRootDir().length()); } for(MatrixConfiguration c: project.getActiveConfigurations()) { - AbstractBuild build = c.getBuildByNumber(1); + AbstractBuild build = c.getBuildByNumber(1); File file = new File(build.getRootDir(), "fileList"); matrixConfigurationBuildsSize.put(c.getDisplayName(), getSize(readFileList(file)) + build.getRootDir().length()); } @@ -136,12 +139,12 @@ public void testExecuteMatrixProject() throws IOException, InterruptedException waitUntilThreadEnds(calculation); Long size = DiskUsageTestUtil.getBuildDiskUsageAction(project.getBuildByNumber(1)).getDiskUsage(); assertEquals("Build " + project.getBuildByNumber(1).getNumber() + " of project " + project.getDisplayName() + " has wrong build size.", matrixProjectBuildSize, size, 0); - for(AbstractBuild build: buildSizesProject2.keySet()) { + for(AbstractBuild build: buildSizesProject2.keySet()) { Long sizeFreeStyle = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), sizeFreeStyle, 0); } for(MatrixConfiguration conf: project.getActiveConfigurations()) { - AbstractBuild build = conf.getBuildByNumber(1); + AbstractBuild build = conf.getBuildByNumber(1); assertEquals("Configuration " + conf.getDisplayName() + " has wrong build size for build 1.", matrixConfigurationBuildsSize.get(conf.getDisplayName()), DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), 0); } @@ -170,9 +173,7 @@ public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throw public void run() { try { testCalculation.execute(TaskListener.NULL); - } catch (IOException ex) { - Logger.getLogger(JobDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); - } catch (InterruptedException ex) { + } catch (IOException | InterruptedException ex) { Logger.getLogger(JobDiskUsageCalculationThreadTest.class.getName()).log(Level.SEVERE, null, ex); } } @@ -184,7 +185,7 @@ public void run() { t.interrupt(); } - public class TestFreeStyleProject extends FreeStyleProject { + public static class TestFreeStyleProject extends FreeStyleProject { public TestFreeStyleProject(ItemGroup group, String name) { super(group, name); @@ -232,7 +233,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception { @Test @LocalData public void testDoNotBreakLazyLoading() throws IOException, InterruptedException { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); // method isBuilding() is used for determining disk usage and its calling load some builds project.isBuilding(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index eac45b46..6085c9f5 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -4,18 +4,18 @@ */ package hudson.plugins.disk_usage.integration; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import hudson.Functions; +import hudson.model.FreeStyleProject; +import hudson.plugins.disk_usage.DiskUsageProperty; import hudson.tasks.BatchFile; import hudson.tasks.Shell; -import java.io.File; -import hudson.FilePath; -import hudson.plugins.disk_usage.DiskUsageProperty; -import hudson.model.AbstractProject; +import org.junit.Rule; import org.junit.Test; -import hudson.model.FreeStyleProject; import org.jvnet.hudson.test.JenkinsRule; -import org.junit.Rule; -import static org.junit.Assert.*; /** * diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 8f46d28c..0f4b2e53 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -4,18 +4,22 @@ */ package hudson.plugins.disk_usage.integration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import org.jvnet.hudson.test.recipes.LocalData; -import hudson.plugins.disk_usage.*; -import org.junit.Test; -import hudson.model.TopLevelItem; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; +import hudson.model.TopLevelItem; +import hudson.plugins.disk_usage.DiskUsagePlugin; +import hudson.plugins.disk_usage.DiskUsageProperty; import java.io.IOException; import org.junit.Rule; +import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; -import static org.junit.Assert.*; +import org.jvnet.hudson.test.recipes.LocalData; /** * @@ -39,8 +43,8 @@ public void testRefreshGlobalInformation() throws IOException { DiskUsageTestUtil.getBuildDiskUsageAction(build2).setDiskUsage(sizeofBuild2); DiskUsageTestUtil.getBuildDiskUsageAction(build3).setDiskUsage(sizeofBuild3); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); - Long workspaceUsage = 20345L; - Long jobUsage = 5980L; + long workspaceUsage = 20345L; + long jobUsage = 5980L; DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { property = new DiskUsageProperty(); @@ -58,7 +62,7 @@ public void testRefreshGlobalInformation() throws IOException { @Test @LocalData public void testNotBreakLazyLoading() throws IOException { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); j.jenkins.getPlugin(DiskUsagePlugin.class).refreshGlobalInformation(); @@ -69,8 +73,8 @@ public void testNotBreakLazyLoading() throws IOException { @Test @LocalData public void testDoNotLoadAllBuildsDuringStart() { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertEquals("Builds of project with disk-usage.xml should not be loaded.", 0, loadedBuilds); loadedBuilds = project2._getRuns().getLoadedBuilds().size(); @@ -80,8 +84,8 @@ public void testDoNotLoadAllBuildsDuringStart() { @Test @LocalData public void testDoLoadBuildInformationWhenBuildIsLoaded() { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuild("1"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractBuild build = project.getBuild("1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Build should be add after its loading (if it is not present before).", property.getDiskUsageOfBuild(2)); @@ -91,12 +95,12 @@ public void testDoLoadBuildInformationWhenBuildIsLoaded() { @Test @LocalData public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuild("2"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractBuild build = project.getBuild("2"); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); j.jenkins.reload(); - project = (AbstractProject) j.jenkins.getItem("project1"); + project = (AbstractProject) j.jenkins.getItem("project1"); build = project.getBuild("2"); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); assertNotNull("Should be loaded build 2", property.getDiskUsageBuildInformation(2)); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 216ffbaa..8ef0fc52 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -1,51 +1,56 @@ package hudson.plugins.disk_usage.integration; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import hudson.FilePath; import hudson.Functions; -import hudson.model.FreeStyleBuild; -import hudson.model.Project; +import hudson.XmlFile; +import hudson.matrix.AxisList; +import hudson.matrix.MatrixBuild; +import hudson.matrix.MatrixConfiguration; +import hudson.matrix.MatrixProject; +import hudson.matrix.TextAxis; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.FreeStyleProject; +import hudson.model.Slave; +import hudson.model.TopLevelItem; +import hudson.model.listeners.RunListener; +import hudson.plugins.disk_usage.DiskUsageBuildInformation; +import hudson.plugins.disk_usage.DiskUsageBuildListener; +import hudson.plugins.disk_usage.DiskUsagePlugin; +import hudson.plugins.disk_usage.DiskUsageProperty; +import hudson.plugins.disk_usage.ProjectDiskUsage; import hudson.plugins.promoted_builds.JobPropertyImpl; import hudson.plugins.promoted_builds.PromotionProcess; import hudson.plugins.promoted_builds.conditions.SelfPromotionCondition; +import hudson.slaves.OfflineCause; import hudson.tasks.BatchFile; -import java.util.ConcurrentModificationException; -import java.util.GregorianCalendar; +import hudson.tasks.Shell; import hudson.util.XStream2; -import hudson.model.AbstractBuild; -import hudson.matrix.MatrixBuild; -import hudson.model.TopLevelItem; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.lang.annotation.Annotation; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRecipe; -import hudson.XmlFile; -import java.util.logging.Level; -import java.util.logging.Logger; -import hudson.model.AbstractProject; +import java.io.File; import java.io.IOException; -import org.jvnet.hudson.test.recipes.LocalData; import java.io.PrintStream; -import hudson.FilePath; -import hudson.tasks.Shell; -import hudson.plugins.disk_usage.*; -import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.ConcurrentModificationException; +import java.util.GregorianCalendar; import java.util.Map; import java.util.Set; -import hudson.model.listeners.RunListener; -import hudson.model.Slave; -import org.junit.Test; -import hudson.matrix.MatrixConfiguration; -import hudson.matrix.AxisList; -import hudson.matrix.TextAxis; -import hudson.matrix.MatrixProject; -import hudson.model.FreeStyleProject; -import hudson.slaves.OfflineCause; +import java.util.logging.Level; +import java.util.logging.Logger; import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRecipe; import org.jvnet.hudson.test.JenkinsRule; -import static org.junit.Assert.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.METHOD; +import org.jvnet.hudson.test.recipes.LocalData; /** * diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index d797f4b7..07ec45f0 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -20,7 +20,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -44,7 +43,7 @@ protected static List readFileList(File file) throws FileNotFoundException } protected static Long getSize(List files) { - Long lenght = 0L; + long lenght = 0L; for(File file: files) { lenght += file.length(); } @@ -62,7 +61,7 @@ protected static Slave createAgent(String name, String remoteFS, Jenkins jenkins return agent; } - protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build) { + protected static BuildDiskUsageAction getBuildDiskUsageAction(AbstractBuild build) { for(Action a: build.getAllActions()) { if(a instanceof BuildDiskUsageAction) { return (BuildDiskUsageAction) a; @@ -80,10 +79,4 @@ protected static void cancelCalculation(DiskUsageCalculation calculation) { } } - protected static void createFileWithContent(File file) throws FileNotFoundException { - file.getParentFile().mkdirs(); - PrintStream stream = new PrintStream(file); - stream.println("hello"); - stream.close(); - } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 38d723a4..3d73f468 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -1,26 +1,32 @@ package hudson.plugins.disk_usage.integration; -import hudson.plugins.disk_usage.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import hudson.matrix.AxisList; import hudson.matrix.LabelAxis; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; import hudson.matrix.TextAxis; -import org.junit.Assert; -import org.jvnet.hudson.test.recipes.LocalData; -import java.util.ArrayList; import hudson.model.AbstractBuild; -import java.io.File; import hudson.model.AbstractProject; import hudson.model.FreeStyleProject; import hudson.model.Slave; import hudson.model.TopLevelItem; import hudson.model.listeners.RunListener; +import hudson.plugins.disk_usage.DiskUsageBuildListener; +import hudson.plugins.disk_usage.DiskUsagePlugin; +import hudson.plugins.disk_usage.DiskUsageProperty; +import hudson.plugins.disk_usage.DiskUsageUtil; +import hudson.plugins.disk_usage.ProjectDiskUsageAction; +import java.io.File; +import java.util.ArrayList; import java.util.List; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; -import static org.junit.Assert.*; +import org.jvnet.hudson.test.recipes.LocalData; /** * @@ -35,7 +41,7 @@ public class DiskUsageUtilTest { @LocalData public void testCalculateDiskUsageForBuild() throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuildByNumber(2); + AbstractBuild build = project.getBuildByNumber(2); File file = new File(build.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + build.getRootDir().length(); DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), project); @@ -46,12 +52,12 @@ public void testCalculateDiskUsageForBuild() throws Exception { @LocalData public void testCalculateDiskUsageForMatrixBuild() throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); - AbstractBuild build = project.getBuildByNumber(1); + AbstractBuild build = project.getBuildByNumber(1); File file = new File(build.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + build.getRootDir().length(); Long sizeAll = size; for(MatrixConfiguration config: project.getActiveConfigurations()) { - AbstractBuild b = config.getBuildByNumber(1); + AbstractBuild b = config.getBuildByNumber(1); File f = new File(b.getRootDir(), "fileList"); sizeAll += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(f)) + b.getRootDir().length(); } @@ -95,7 +101,7 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception { } DiskUsageUtil.calculateDiskUsageForProject(project); Assert.assertEquals("Calculation of job disk usage does not return right size of job without builds.", size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds()); - for(AbstractProject p: project.getItems()) { + for(AbstractProject p: project.getItems()) { DiskUsageUtil.calculateDiskUsageForProject(p); } Assert.assertEquals("Calculation of job disk usage does not return right size of job and its sub-jobs without builds.", sizeAll, project.getAction(ProjectDiskUsageAction.class).getAllDiskUsageWithoutBuilds()); @@ -106,7 +112,7 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception { @LocalData public void testCalculateDiskUsageWorkspaceForProject() throws Exception { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -136,7 +142,7 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception { @LocalData public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory() throws Exception { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); j.jenkins.setNumExecutors(0); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -215,7 +221,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa @LocalData public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() throws Exception { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsagePlugin plugin = j.jenkins.getPlugin(DiskUsagePlugin.class); plugin.getConfiguration().setCheckWorkspaceOnAgent(true); @@ -250,7 +256,7 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t @Test public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception { - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); Slave agent2 = DiskUsageTestUtil.createAgent("agent2", new File(j.jenkins.getRootDir(), "workspace2").getPath(), j.jenkins, j.createComputerLauncher(null)); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index fe5a7b1c..25e18612 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -3,13 +3,17 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import hudson.plugins.disk_usage.*; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; import hudson.model.AperiodicWork; import hudson.model.FreeStyleProject; import hudson.model.TaskListener; import hudson.model.listeners.RunListener; +import hudson.plugins.disk_usage.DiskUsageBuildListener; +import hudson.plugins.disk_usage.DiskUsageProjectActionFactory; +import hudson.plugins.disk_usage.DiskUsageProperty; +import hudson.plugins.disk_usage.JobWithoutBuildsDiskUsageCalculation; +import hudson.plugins.disk_usage.ProjectDiskUsageAction; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -55,7 +59,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long length = 0L; + long length = 0L; for(File file: files) { length += file.length(); } @@ -66,7 +70,7 @@ private Long getSize(List files) { @LocalData public void testExecute() throws IOException, InterruptedException { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); @@ -75,9 +79,9 @@ public void testExecute() throws IOException, InterruptedException { project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); - Long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); + long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); file = new File(project2.getRootDir(), "fileList"); - Long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); + long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); projectSize += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); @@ -95,7 +99,7 @@ public void testExecute() throws IOException, InterruptedException { public void testMatrixProject() throws IOException, InterruptedException { // turn off run listener DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Map matrixConfigurationsSize = new TreeMap<>(); MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); @@ -104,15 +108,15 @@ public void testMatrixProject() throws IOException, InterruptedException { project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); project2.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File file = new File(project.getRootDir(), "fileList"); - Long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); + long projectSize = getSize(readFileList(file)) + project.getRootDir().length(); file = new File(project2.getRootDir(), "fileList"); - Long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); + long project2Size = getSize(readFileList(file)) + project2.getRootDir().length(); projectSize += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); project2Size += project2.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); for(MatrixConfiguration config: project.getItems()) { config.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); File f = new File(config.getRootDir(), "fileList"); - Long size = getSize(readFileList(f)) + config.getRootDir().length(); + long size = getSize(readFileList(f)) + config.getRootDir().length(); long diskUsageXML = config.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); matrixConfigurationsSize.put(config.getDisplayName(), size + diskUsageXML); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 11a1cdcf..03763bc7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -1,31 +1,32 @@ package hudson.plugins.disk_usage.integration; -import hudson.model.AbstractProject; -import org.jvnet.hudson.test.recipes.LocalData; -import hudson.plugins.disk_usage.*; -import hudson.model.TopLevelItem; -import hudson.model.Project; -import hudson.model.Build; -import hudson.model.TopLevelItemDescriptor; -import java.util.Map; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Calendar; -import java.io.File; -import java.io.IOException; -import hudson.model.ItemGroup; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import hudson.matrix.AxisList; import hudson.matrix.MatrixBuild; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; import hudson.matrix.TextAxis; import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Build; import hudson.model.FreeStyleProject; +import hudson.model.ItemGroup; +import hudson.model.Project; +import hudson.model.TopLevelItem; +import hudson.model.TopLevelItemDescriptor; import hudson.model.listeners.ItemListener; +import hudson.plugins.disk_usage.ProjectDiskUsageAction; +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Map; +import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; -import org.junit.Rule; -import static org.junit.Assert.*; +import org.jvnet.hudson.test.recipes.LocalData; /** * @@ -47,7 +48,7 @@ public void testGetBuildsDiskUsage() throws Exception { list.add(axis2); matrixProject.setAxes(list); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); @@ -61,13 +62,13 @@ public void testGetBuildsDiskUsage() throws Exception { long size1 = 5390; long size2 = 2390; int count = 1; - Long matrixBuild1TotalSize = sizeOfMatrixBuild1; - Long matrixBuild2TotalSize = sizeOfMatrixBuild2; + long matrixBuild1TotalSize = sizeOfMatrixBuild1; + long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()) { - AbstractBuild configurationBuild = c.getBuildByNumber(1); + AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count * size1; - AbstractBuild configurationBuild2 = c.getBuildByNumber(2); + AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count * size2; count++; @@ -89,27 +90,27 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { list.add(axis2); matrixProject.setAxes(list); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild1 = matrixProject.getLastBuild(); j.buildAndAssertSuccess(matrixProject); MatrixBuild matrixBuild2 = matrixProject.getLastBuild(); Long sizeofBuild = 7546L; Long sizeOfMatrixBuild1 = 6800L; - Long sizeOfMatrixBuild2 = 14032L; + long sizeOfMatrixBuild2 = 14032L; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); long size1 = 5390; long size2 = 2390; int count = 1; - Long matrixBuild1TotalSize = sizeOfMatrixBuild1; - Long matrixBuild2TotalSize = sizeOfMatrixBuild2; + long matrixBuild1TotalSize = sizeOfMatrixBuild1; + long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()) { - AbstractBuild configurationBuild = c.getBuildByNumber(1); + AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count * size1; - AbstractBuild configurationBuild2 = c.getBuildByNumber(2); + AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); matrixBuild2TotalSize += count * size2; count++; @@ -144,7 +145,7 @@ public void getAllBuildDiskUsageFiltered() throws Exception { Date olderThan5months = filterCalendar.getTime(); filterCalendar.set(2013, 8, 19); Date olderThan3weeks = filterCalendar.getTime(); - Long sizeofBuild1 = 7546L; + long sizeofBuild1 = 7546L; Long sizeofBuild2 = 9546L; Long sizeofBuild3 = 15546L; DiskUsageTestUtil.getBuildDiskUsageAction(build1).setDiskUsage(sizeofBuild1); @@ -170,7 +171,7 @@ public void getAllBuildDiskUsageFiltered() throws Exception { @Test @LocalData public void testNotToBreakLazyLoading() throws IOException { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); @@ -206,6 +207,7 @@ public ProjectTestBuild createExecutable(Calendar calendar) throws IOException { return build; } + @Override public TopLevelItemDescriptor getDescriptor() { throw new UnsupportedOperationException("Not supported yet."); } @@ -232,10 +234,6 @@ public ProjectTestBuild(ProjectTest project, Calendar calendar) throws IOExcepti super(project, calendar); } - public ProjectTestBuild(ProjectTest project, File buildDir) throws IOException { - super(project, buildDir); - } - } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java index 2178660f..410db141 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java @@ -4,9 +4,12 @@ */ package hudson.plugins.disk_usage.integration; -import hudson.plugins.disk_usage.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import hudson.model.AbstractProject; import hudson.plugins.disk_usage.DiskUsageBuildInformation; +import hudson.plugins.disk_usage.DiskUsageProperty; import hudson.plugins.disk_usage.ProjectDiskUsageAction; import java.io.IOException; import java.util.Set; @@ -14,7 +17,6 @@ import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.recipes.LocalData; -import static org.junit.Assert.*; /** * @@ -29,7 +31,7 @@ public class ProjectDiskUsageTest { @Test @LocalData public void testAllInfoLoaded() throws IOException { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); Set informations = project.getAction(ProjectDiskUsageAction.class).getBuildsInformation(); @@ -41,16 +43,17 @@ public void testAllInfoLoaded() throws IOException { @Test @LocalData public void testFirstLoad() throws IOException { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - Set informations = ((DiskUsageProperty) project.getProperty(DiskUsageProperty.class)).getDiskUsage().getBuildDiskUsage(false); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + Set informations = project.getProperty(DiskUsageProperty.class) + .getDiskUsage().getBuildDiskUsage(false); assertEquals("Set of DisUsageBuildInformation should not contain information about builds because they are not loaded.", 0, informations.size()); } @Test @LocalData public void testLoadingAllBuildInformationFromPreviousVersion() { - AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); assertEquals("Builds information should be loaded.", 8, property.getDiskUsage().getBuildDiskUsage(true).size(), 0); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index bc5ce3c0..c5afc766 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -9,7 +9,6 @@ import static org.junit.Assert.assertTrue; import hudson.Functions; -import hudson.plugins.disk_usage.*; import hudson.matrix.AxisList; import hudson.matrix.MatrixProject; import hudson.matrix.TextAxis; @@ -22,6 +21,12 @@ import hudson.model.Slave; import hudson.model.TaskListener; import hudson.model.listeners.RunListener; +import hudson.plugins.disk_usage.BuildDiskUsageCalculationThread; +import hudson.plugins.disk_usage.DiskUsageBuildListener; +import hudson.plugins.disk_usage.DiskUsageProjectActionFactory; +import hudson.plugins.disk_usage.DiskUsageProperty; +import hudson.plugins.disk_usage.ProjectDiskUsageAction; +import hudson.plugins.disk_usage.WorkspaceDiskUsageCalculationThread; import hudson.slaves.DumbSlave; import hudson.slaves.NodeProperty; import hudson.slaves.RetentionStrategy; @@ -81,7 +86,7 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - Long length = 0L; + long length = 0L; for(File file: files) { length += file.length(); @@ -104,7 +109,7 @@ private Slave createAgent(String name, String remoteFS) throws Exception { @LocalData public void testExecute() throws IOException, InterruptedException, Exception { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); Slave agent2 = createAgent("agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); @@ -137,7 +142,7 @@ public void testExecute() throws IOException, InterruptedException, Exception { @LocalData public void testExecuteMatrixProject() throws Exception { // turn off run listener - RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); + RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); j.getInstance().setNumExecutors(0); Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); @@ -252,7 +257,7 @@ public void run() { @Test @LocalData public void testDoNotBreakLazyLoading() throws Exception { - AbstractProject project = (AbstractProject) j.getInstance().getItem("project1"); + AbstractProject project = (AbstractProject) j.getInstance().getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); @@ -300,7 +305,7 @@ public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { j.buildAndAssertSuccess(job); j.buildAndAssertSuccess(job); File file = new File(agent1.getWorkspaceFor(job).getRemote(), "fileList"); - Long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(job).length(); + long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(job).length(); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces()); diff --git a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java index 386977bf..498cfeb9 100644 --- a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java @@ -1,14 +1,15 @@ package hudson.plugins.disk_usage.project.integration; +import static org.junit.Assert.assertTrue; + import hudson.matrix.MatrixProject; -import hudson.plugins.disk_usage.project.DiskUsagePostBuildCalculation; -import hudson.plugins.disk_usage.BuildDiskUsageAction; -import org.junit.Test; import hudson.model.AbstractBuild; import hudson.model.FreeStyleProject; -import org.jvnet.hudson.test.JenkinsRule; +import hudson.plugins.disk_usage.BuildDiskUsageAction; +import hudson.plugins.disk_usage.project.DiskUsagePostBuildCalculation; import org.junit.Rule; -import static org.junit.Assert.*; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; /** * @@ -24,7 +25,7 @@ public void testDiskUsageIsCalculated() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); } @@ -34,7 +35,7 @@ public void testDiskUsageIsNotCalculatedTwoTimes() throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage called by listener should be skipped.", build.getLog(10).contains("Skipping calculation of disk usage, it was already done in post build step.")); } @@ -43,7 +44,7 @@ public void testDiskUsageCalculationForMatrixProject() throws Exception { MatrixProject project = j.jenkins.createProject(MatrixProject.class, "project"); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); - AbstractBuild build = project.getLastBuild(); + AbstractBuild build = project.getLastBuild(); assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); } From c51e4350b2a746a2e66a17aa6c639651da5f8f1d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 17 Mar 2023 00:49:33 +0000 Subject: [PATCH 082/158] Replace Jenkins.getInstance() with Jenkins.get() --- .../BuildDiskUsageCalculationThread.java | 13 +++++----- .../disk_usage/DiskUsageItemListener.java | 2 +- .../disk_usage/DiskUsageManagement.java | 2 +- .../DiskUsageOvearallGraphGenerator.java | 4 ++-- .../plugins/disk_usage/DiskUsagePlugin.java | 14 +++++------ .../DiskUsageProjectActionFactory.java | 2 +- .../plugins/disk_usage/DiskUsageProperty.java | 18 +++++++------- .../plugins/disk_usage/DiskUsageUtil.java | 24 +++++++++---------- .../JobWithoutBuildsDiskUsageCalculation.java | 11 ++++----- .../plugins/disk_usage/ProjectDiskUsage.java | 2 +- .../disk_usage/ProjectDiskUsageAction.java | 2 +- .../WorkspaceDiskUsageCalculationThread.java | 13 +++++----- 12 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index b5eaba62..bb33b2b5 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -37,14 +37,13 @@ public BuildDiskUsageCalculationThread() { public void execute(TaskListener listener) throws IOException, InterruptedException { if(!isCancelled() && startExecution()) { try { - List items = new ArrayList<>(); - ItemGroup itemGroup = Jenkins.getInstance(); - items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); + ItemGroup itemGroup = Jenkins.get(); + List items = new ArrayList<>(DiskUsageUtil.getAllProjects(itemGroup)); for(Object item: items) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; - DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); + DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); if(property == null) { property = new DiskUsageProperty(); project.addProperty(property); @@ -72,7 +71,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } } else { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(plugin.getConfiguration().isCalculationBuildsEnabled()) { logger.log(Level.FINER, "Calculation of builds is already in progress."); } @@ -84,7 +83,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); + String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); return new CronTab(cron); } @@ -106,7 +105,7 @@ public DiskUsageCalculation getLastTask() { } private boolean startExecution() { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationBuildsEnabled()) { return false; } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java index 020b06db..5266b5f4 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageItemListener.java @@ -45,7 +45,7 @@ public void onCopied(Item src, Item item) { @Override public void onLoaded() { - for(Item item: Jenkins.getInstance().getItems()) { + for(Item item: Jenkins.get().getItems()) { DiskUsageUtil.addProperty(item); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 9fc659e7..356a2f5d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -50,7 +50,7 @@ public Category getCategory() { } public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { - res.sendRedirect(Jenkins.getInstance().getRootUrlFromRequest() + "plugin/disk-usage"); + res.sendRedirect(Jenkins.get().getRootUrlFromRequest() + "plugin/disk-usage"); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 47d0cde3..afa10487 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -26,9 +26,9 @@ public long getRecurrencePeriod() { @Override protected void doRun() throws Exception { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); plugin.refreshGlobalInformation(); - File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); + File jobsDir = new File(Jenkins.get().getRootDir(), "jobs"); Long freeJobsDirSpace = jobsDir.getTotalSpace(); DiskUsageProjectActionFactory.DESCRIPTOR.addHistory(new DiskUsageOvearallGraphGenerator.DiskUsageRecord(plugin.getCashedGlobalBuildsDiskUsage(), plugin.getGlobalAgentDiskUsageWorkspace(), plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), freeJobsDirSpace, plugin.getCashedNonAgentDiskUsageWorkspace())); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java index 175582a9..5dbc2640 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsagePlugin.java @@ -42,7 +42,7 @@ public void refreshGlobalInformation() throws IOException { diskUsageJobsWithoutBuilds = 0L; diskUsageLockedBuilds = 0L; diskUsageNonAgentWorkspaces = 0L; - for(Item item: Jenkins.getInstance().getItems()) { + for(Item item: Jenkins.get().getItems()) { if(item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); @@ -177,7 +177,7 @@ public List getProjectList() throws IOException { return 0; }; - List projectList = Jenkins.getInstance().getAllItems(AbstractProject.class); + List projectList = Jenkins.get().getAllItems(AbstractProject.class); projectList.sort(comparator); return projectList; @@ -198,7 +198,7 @@ public DiskUsageProjectActionFactory.DescriptorImpl getConfiguration() { } public Graph getOverallGraph() { - File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); + File jobsDir = new File(Jenkins.get().getRootDir(), "jobs"); long maxValue = getCashedGlobalJobsDiskUsage(); if(getConfiguration().getShowFreeSpaceForJobDirectory()) { maxValue = jobsDir.getTotalSpace(); @@ -245,7 +245,7 @@ public Graph getOverallGraph() { } public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationBuildsEnabled() && !getBuildsDiskUsageThread().isExecuting()) { getBuildsDiskUsageThread().doAperiodicRun(); } @@ -253,7 +253,7 @@ public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) thro } public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationJobsEnabled() && !getJobsDiskUsageThread().isExecuting()) { getJobsDiskUsageThread().doAperiodicRun(); } @@ -261,7 +261,7 @@ public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throw } public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationWorkspaceEnabled() && !getWorkspaceDiskUsageThread().isExecuting()) { getWorkspaceDiskUsageThread().doAperiodicRun(); } @@ -294,7 +294,7 @@ public String getCountIntervalForWorkspaces() { } public boolean hasAdministrativePermission() { - return Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER); + return Jenkins.get().hasPermission(Jenkins.ADMINISTER); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 2764b7fd..4680b5ad 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -300,7 +300,7 @@ public DiskUsageProjectActionFactory newInstance(StaplerRequest req, @NonNull JS @Override public boolean configure(StaplerRequest req, JSONObject formData) { - Jenkins.getInstance().checkPermission(Permission.CONFIGURE); + Jenkins.get().checkPermission(Permission.CONFIGURE); JSONObject form; try { form = req.getSubmittedForm(); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index c006ac65..22dcaafe 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -214,10 +214,10 @@ public void putAgentWorkspaceSize(Node node, String path, Long size) { public Long getWorkspaceSize(Boolean containdedInWorkspace) { Long size = 0L; for(String nodeName: getAgentWorkspaceUsage().keySet()) { - Node node = Jenkins.getInstance().getNode(nodeName); + Node node = Jenkins.get().getNode(nodeName); String workspacePath = null; if(node instanceof Jenkins) { - workspacePath = Jenkins.getInstance().getRawWorkspaceDir(); + workspacePath = Jenkins.get().getRawWorkspaceDir(); } if(node instanceof Slave) { workspacePath = ((Slave) node).getRemoteFS(); @@ -298,8 +298,8 @@ public void checkWorkspaces(boolean force) { checkLoadedBuilds(); } // only if it is wanted - can cost a quite long time to do it for all - if(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnAgent() && owner instanceof TopLevelItem) { - for(Node node: Jenkins.getInstance().getNodes()) { + if(Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnAgent() && owner instanceof TopLevelItem) { + for(Node node: Jenkins.get().getNodes()) { if(node.toComputer() != null && node.toComputer().isOnline()) { FilePath path = null; try { @@ -320,9 +320,9 @@ public void checkWorkspaces(boolean force) { Iterator iterator = diskUsage.slaveWorkspacesUsage.keySet().iterator(); while(iterator.hasNext()) { String nodeName = iterator.next(); - Node node = Jenkins.getInstance().getNode(nodeName); + Node node = Jenkins.get().getNode(nodeName); if(node == null && nodeName.isEmpty()) { - node = Jenkins.getInstance(); + node = Jenkins.get(); } // delete name of agents which do not exist if(node == null) {// Jenkins master has empty name @@ -364,10 +364,10 @@ public Long getAllNonAgentOrCustomWorkspaceSize() { for(String nodeName: getAgentWorkspaceUsage().keySet()) { Node node = null; if(nodeName.isEmpty()) { - node = Jenkins.getInstance(); + node = Jenkins.get(); } else { - node = Jenkins.getInstance().getNode(nodeName); + node = Jenkins.get().getNode(nodeName); } if(node == null) { // agent does not exist continue; @@ -405,7 +405,7 @@ private boolean isContainedInWorkspace(Item item, Node node, String path) { if (item instanceof TopLevelItem){ TopLevelItem topLevelItem = (TopLevelItem) item; if(node instanceof Jenkins) { - FilePath file = Jenkins.getInstance().getWorkspaceFor(topLevelItem); + FilePath file = Jenkins.get().getWorkspaceFor(topLevelItem); if (file != null){ return path.contains(file.getRemote()); } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 769a6bcf..688a20dd 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -128,7 +128,7 @@ public static String formatTimeInMilisec(long time) { public static void sendEmail(String subject, String message) throws MessagingException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); String address = plugin.getConfiguration().getEmailAddress(); if(address == null || address.isEmpty()) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "e-mail addres is not set for notification about exceed disk size. Please set it in global configuration."); @@ -155,7 +155,7 @@ public static Long getSizeInBytes(String stringSize) { } public static void controlAllJobsExceedSize() throws IOException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); plugin.refreshGlobalInformation(); Long allJobsSize = plugin.getCashedGlobalJobsDiskUsage(); Long exceedJobsSize = plugin.getConfiguration().getAllJobsExceedSize(); @@ -169,7 +169,7 @@ public static void controlAllJobsExceedSize() throws IOException { } public static void controlWorkspaceExceedSize(AbstractProject project) { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { @@ -203,7 +203,7 @@ public static List parseExcludedJobsFromString(String jobs) { String[] jobNames = jobs.split(","); for(String name: jobNames) { name = name.trim(); - Item item = Jenkins.getInstance().getItem(name); + Item item = Jenkins.get().getItem(name); if(item != null && item instanceof AbstractProject) { list.add(name); } @@ -284,7 +284,7 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener try { // count build.xml too build.save(); - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); listener.getLogger().println("Started calculate disk usage of build"); Long startTimeOfBuildCalculation = System.currentTimeMillis(); DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), build.getProject()); @@ -364,7 +364,7 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; } - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); List exceededFiles = new ArrayList<>(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { @@ -373,7 +373,7 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws } Set informations = (Set) property.getDiskUsage().getBuildDiskUsage(true); for(DiskUsageBuildInformation information: informations) { - exceededFiles.add(new File(Jenkins.getInstance().getBuildDirFor(project), information.getId())); + exceededFiles.add(new File(Jenkins.get().getBuildDirFor(project), information.getId())); } if(project instanceof ItemGroup) { List projects = getAllProjects((ItemGroup) project); @@ -406,10 +406,10 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr if(DiskUsageProjectActionFactory.DESCRIPTOR.isExcluded(project)) { return; } - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); // Build disk usage has to be always recalculated to be kept up-to-date // - artifacts might be kept only for the last build and users sometimes delete files manually as well. - long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.getInstance().getBuildDirFor(project), buildId), new ArrayList<>()); + long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.get().getBuildDirFor(project), buildId), new ArrayList<>()); Collection loadedBuilds = project._getRuns().getLoadedBuilds().values(); AbstractBuild build = null; @@ -457,7 +457,7 @@ public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayL Long diskUsage = 0L; if(workspace.exists()) { try { - diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); + diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); } catch (Exception e) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage fails to calculate workspace for file path " + workspace.getRemote() + " through channel " + workspace.getChannel(), e); @@ -480,10 +480,10 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I for(String nodeName: property.getAgentWorkspaceUsage().keySet()) { Node node = null; if(nodeName.isEmpty()) { - node = Jenkins.getInstance(); + node = Jenkins.get(); } else { - node = Jenkins.getInstance().getNode(nodeName); + node = Jenkins.get().getNode(nodeName); } if(node == null) { // probably does not exists yet diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 6224025f..b9734199 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -35,12 +35,11 @@ public JobWithoutBuildsDiskUsageCalculation() { @Override public void execute(TaskListener listener) throws IOException, InterruptedException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(!isCancelled() && startExecution()) { try { - List items = new ArrayList<>(); - ItemGroup itemGroup = Jenkins.getInstance(); - items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); + ItemGroup itemGroup = Jenkins.get(); + List items = new ArrayList<>(DiskUsageUtil.getAllProjects(itemGroup)); for(Object item: items) { if(item instanceof AbstractProject) { @@ -88,7 +87,7 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForJobs(); + String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForJobs(); return new CronTab(cron); } @@ -98,7 +97,7 @@ public DiskUsageCalculation getLastTask() { } private boolean startExecution() { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationJobsEnabled()) { return false; } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index 1333e76f..f6b2a8a7 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -196,7 +196,7 @@ private void removeDeletedBuilds() { Iterator iterator = buildDiskUsage.iterator(); while(iterator.hasNext()) { DiskUsageBuildInformation information = iterator.next(); - File buildDir = new File(Jenkins.getInstance().getBuildDirFor(job), information.getId()); + File buildDir = new File(Jenkins.get().getBuildDirFor(job), information.getId()); if(!buildDir.exists()) { buildDiskUsage.remove(information); } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index a735c9b2..3cfb3821 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -335,6 +335,6 @@ public Graph getGraph() throws IOException { /** Shortcut for the jelly view */ public boolean showGraph() { - return Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().isShowGraph(); + return Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().isShowGraph(); } } diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 9dc8e421..ef197016 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -34,15 +34,14 @@ public WorkspaceDiskUsageCalculationThread() { @Override public void execute(TaskListener listener) throws IOException, InterruptedException { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(!isCancelled() && startExecution()) { try { - List items = new ArrayList<>(); - ItemGroup itemGroup = Jenkins.getInstance(); - items.addAll(DiskUsageUtil.getAllProjects(itemGroup)); + ItemGroup itemGroup = Jenkins.get(); + List items = new ArrayList<>(DiskUsageUtil.getAllProjects(itemGroup)); for(Object item: items) { if(item instanceof AbstractProject) { - AbstractProject project = (AbstractProject) item; + AbstractProject project = (AbstractProject) item; // do not count workspace for running project if(project.isBuilding()) { continue; @@ -84,7 +83,7 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForWorkspaces(); + String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForWorkspaces(); return new CronTab(cron); } @@ -94,7 +93,7 @@ public DiskUsageCalculation getLastTask() { } private boolean startExecution() { - DiskUsagePlugin plugin = Jenkins.getInstance().getPlugin(DiskUsagePlugin.class); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if(!plugin.getConfiguration().isCalculationWorkspaceEnabled()) { return false; } From dd27341088aa9cd8cf8bf78a8387fce68f99de3c Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 17 Mar 2023 10:42:38 +0000 Subject: [PATCH 083/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a79cdab4..61a468d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [Upgrade from javax.mail to jakarta.mail](https://github.com/jenkinsci/disk-usage-plugin/pull/76) - [Fixes class cast exception with promoted builds plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/77) - [Removes deprecated fields from BuildDiskUsageAction](https://github.com/jenkinsci/disk-usage-plugin/pull/79) +- [Fix various warnings](https://github.com/jenkinsci/disk-usage-plugin/pull/80) ### Release 0.28 (Oct 01, 2015) From 275b4c336271fd70a87f011f6e0edf5dc9bee8e1 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:08:02 +0000 Subject: [PATCH 084/158] Removes deprecated code in DiskUsageProperty It has been over 7 years, all Jenkins installations should be converted by now. --- .../plugins/disk_usage/DiskUsageProperty.java | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 22dcaafe..02895200 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -478,21 +478,6 @@ private Long getDiskUsageWithoutBuildsAllSubItems(ItemGroup group) { return usage; } - @Initializer(after = InitMilestone.PLUGINS_STARTED) - public static void transitionAuth() throws IOException { - DiskUsageDescriptor that = (DiskUsageDescriptor) Hudson.getInstance().getDescriptor(DiskUsageProperty.class); - if(that == null) { - LOGGER.warning("Cannot convert DiskUsageProjectActions, DiskUsageDescripto is null, check log for previous DI error, e.g. Guice errors."); - return; - } - if(!that.converted) { - DiskUsageProjectActionFactory.DESCRIPTOR.setShowGraph(that.showGraph); - that.converted = true; - that.save(); - DiskUsageProjectActionFactory.DESCRIPTOR.save(); - } - } - public void saveDiskUsage() { diskUsage.save(); } @@ -518,29 +503,11 @@ public JobProperty reconfigure(StaplerRequest req, JSONObject form) throws De @Extension public static final class DiskUsageDescriptor extends JobPropertyDescriptor { - @Deprecated - private boolean showGraph; - - @Deprecated - private boolean converted; - - public DiskUsageDescriptor() { - load(); - } - @Override public String getDisplayName() { return Messages.displayName(); } - public boolean showGraph() { - return showGraph; - } - - @Override - public boolean isApplicable(Class jobType) { - return true; - } } public static final Logger LOGGER = Logger.getLogger(DiskUsageProperty.class.getName()); From 5a0cc6cdc7da6413d656b806b7663d50f5028972 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:21:58 +0000 Subject: [PATCH 085/158] Replaces deprecated perform method in DiskUsagePostBuildCalculation --- .../project/DiskUsagePostBuildCalculation.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java index 7c1ab7c0..031bdb58 100644 --- a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java @@ -7,6 +7,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.Launcher; +import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Build; import hudson.model.BuildListener; @@ -15,6 +16,7 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; +import java.io.IOException; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; @@ -24,17 +26,15 @@ */ public class DiskUsagePostBuildCalculation extends Recorder { - public DiskUsagePostBuildCalculation() { - } - @Override - public boolean perform(Build build, Launcher launcher, BuildListener listener) { + public boolean perform(final AbstractBuild build, final Launcher launcher, final BuildListener listener) + throws InterruptedException, IOException + { listener.getLogger().println("append disk usage"); DiskUsageUtil.calculationDiskUsageOfBuild(build, listener); return true; } - @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; From 68dccee6fe990a8a69ac39b335af39e0c85f736e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:23:19 +0000 Subject: [PATCH 086/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a468d6..cb6a689f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - [Fixes class cast exception with promoted builds plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/77) - [Removes deprecated fields from BuildDiskUsageAction](https://github.com/jenkinsci/disk-usage-plugin/pull/79) - [Fix various warnings](https://github.com/jenkinsci/disk-usage-plugin/pull/80) +- [Removes deprecated code in DiskUsageProperty](https://github.com/jenkinsci/disk-usage-plugin/pull/81) ### Release 0.28 (Oct 01, 2015) From c6d3c700fdee575edcf11f64c49bd426032c9094 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:30:48 +0000 Subject: [PATCH 087/158] Removes deprecated DiskUsage and inline fields into child DiskUsageRecord --- .../hudson/plugins/disk_usage/DiskUsage.java | 26 ------------------- .../DiskUsageOvearallGraphGenerator.java | 8 +++--- 2 files changed, 5 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/hudson/plugins/disk_usage/DiskUsage.java diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsage.java b/src/main/java/hudson/plugins/disk_usage/DiskUsage.java deleted file mode 100644 index 8fc57b1f..00000000 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsage.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package hudson.plugins.disk_usage; - -/** - * - * @author dvrzalik - * Due to backward compatibility - */ -@Deprecated -public class DiskUsage { - - public DiskUsage() { - } - - public DiskUsage(Long buildUsage, Long wsUsage) { - this.buildUsage = buildUsage; - this.wsUsage = wsUsage; - } - - Long buildUsage; - Long wsUsage; - -} diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index afa10487..18220bd5 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -35,16 +35,18 @@ protected void doRun() throws Exception { DiskUsageProjectActionFactory.DESCRIPTOR.save(); } - public static class DiskUsageRecord extends DiskUsage { + public static class DiskUsageRecord { private static final SimpleDateFormat sdf = new SimpleDateFormat("d/M"); Date date; private Long jobsWithoutBuildsUsage = 0L; private Long allSpace = 0L; private Long diskUsageNonAgentWorkspaces = 0L; - + private Long buildUsage; + private Long wsUsage; public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long diskUsageJobsWithoutBuilds, Long allSpace, Long diskUsageNonAgentWorkspaces) { - super(diskUsageBuilds, diskUsageWorkspaces); + this.buildUsage = diskUsageBuilds; + this.wsUsage = diskUsageWorkspaces; this.jobsWithoutBuildsUsage = diskUsageJobsWithoutBuilds; this.allSpace = allSpace; this.diskUsageNonAgentWorkspaces = diskUsageNonAgentWorkspaces; From d2ef89f3982993b7e5ad2d628f2d64e2de89f51e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:33:57 +0000 Subject: [PATCH 088/158] Removes unused class ProjectConfigListener --- .../disk_usage/ProjectConfigListener.java | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java b/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java deleted file mode 100644 index dc899d03..00000000 --- a/src/main/java/hudson/plugins/disk_usage/ProjectConfigListener.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package hudson.plugins.disk_usage; - -import hudson.Extension; -import hudson.model.listeners.SaveableListener; - -/** - * - * @author Lucie Votypkova - */ -@Extension -public class ProjectConfigListener extends SaveableListener { - - -} From 80f2b7491b0619a8b99bfd5d26fe5217d5665f70 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 22:36:20 +0000 Subject: [PATCH 089/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb6a689f..12869d0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - [Removes deprecated fields from BuildDiskUsageAction](https://github.com/jenkinsci/disk-usage-plugin/pull/79) - [Fix various warnings](https://github.com/jenkinsci/disk-usage-plugin/pull/80) - [Removes deprecated code in DiskUsageProperty](https://github.com/jenkinsci/disk-usage-plugin/pull/81) +- [Replaces deprecated perform method in DiskUsagePostBuildCalculation](https://github.com/jenkinsci/disk-usage-plugin/pull/82) ### Release 0.28 (Oct 01, 2015) From 5b791291bd6e30ba8ffdcacf189385205ac7a439 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 23:11:22 +0000 Subject: [PATCH 090/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12869d0f..049a24dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [Fix various warnings](https://github.com/jenkinsci/disk-usage-plugin/pull/80) - [Removes deprecated code in DiskUsageProperty](https://github.com/jenkinsci/disk-usage-plugin/pull/81) - [Replaces deprecated perform method in DiskUsagePostBuildCalculation](https://github.com/jenkinsci/disk-usage-plugin/pull/82) +- [Removes deprecated DiskUsage and inline fields into child DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/83) ### Release 0.28 (Oct 01, 2015) From 767b011321001d6eb77c0294186641cb3ebb6b5b Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 18 Mar 2023 23:13:54 +0000 Subject: [PATCH 091/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 049a24dd..ff74d063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [Removes deprecated code in DiskUsageProperty](https://github.com/jenkinsci/disk-usage-plugin/pull/81) - [Replaces deprecated perform method in DiskUsagePostBuildCalculation](https://github.com/jenkinsci/disk-usage-plugin/pull/82) - [Removes deprecated DiskUsage and inline fields into child DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/83) +- [Removes unused class ProjectConfigListener](https://github.com/jenkinsci/disk-usage-plugin/pull/84) ### Release 0.28 (Oct 01, 2015) From b70f5ace08962d6b9acbbaf2272cbb4957369984 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 19 Mar 2023 00:24:04 +0000 Subject: [PATCH 092/158] Fix spelling errors Used https://github.com/crate-ci/typos to detected errors. --- CHANGELOG.md | 10 +++++----- README.md | 4 ++-- .../disk_usage/DiskUsageCalculation.java | 2 +- .../plugins/disk_usage/DiskUsageUtil.java | 14 +++++++------- .../project/DiskUsagePostBuildCalculation.java | 2 +- .../DiskUsageProjectActionFactory/global.jelly | 2 +- .../disk_usage/DiskUsageCalculationTest.java | 18 +++++++++--------- .../BuildDiskUsageCalculationThreadTest.java | 17 +++++++++-------- .../integration/DiskUsagePropertyTest.java | 8 ++++---- .../integration/DiskUsageTestUtil.java | 6 +++--- .../integration/DiskUsageUtilTest.java | 4 ++-- .../JobDiskUsageCalculationThreadTest.java | 12 +++++++----- ...orkspaceDiskUsageCalculationThreadTest.java | 2 +- 13 files changed, 52 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff74d063..f531abd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,10 +76,10 @@ tasks. - Reverse build order in graph - Make graph huger - Make free space in job directory optional in global graph -- Better sheduling automatic calculation +- Better scheduling automatic calculation - Move information about project disk usage form config.xml of job - Fixing typo direcotory -\> directory -- Display next execution time and add buttom for builds, jobs and +- Display next execution time and add bottom for builds, jobs and workspaces - Fix link in menu on main page @@ -93,7 +93,7 @@ tasks. - Fix test - Display all workspaces - Save history -- Fix backward compatibility, fix concurent modification exception and +- Fix backward compatibility, fix concurrent modification exception and make timeout workspace configurable - Replace Util.isSymlink - Fix backward compatibility @@ -106,7 +106,7 @@ tasks. - Correct information about author - Add tests for case the slave is deleted or workspace of project was deleted -- Fix problems with claculation threads and removing workspaces form +- Fix problems with calculation threads and removing workspaces form diskUsage set if do not exist or its slave does not exists - Add tests - Fix problems with symlinks @@ -159,7 +159,7 @@ tasks. ### Release 0.17 (May 24, 2012) -- Added support for hierachical job model ([pull +- Added support for hierarchical job model ([pull \#6](https://github.com/jenkinsci/disk-usage-plugin/pull/6)) - Fixed broken showGraph ([pull \#7](https://github.com/jenkinsci/disk-usage-plugin/pull/7))  diff --git a/README.md b/README.md index f6d24cb9..7911c9da 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,6 @@ More detailed information can be seen on the project page, where you can find di ![](docs/images/du-project.png) -You can configurate the plugin in `Manage Jenkins` -> `Configure System` +You can configure the plugin in `Manage Jenkins` -> `Configure System` -![](docs/images/du-configuration.png) \ No newline at end of file +![](docs/images/du-configuration.png) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 762db054..1b7e3b33 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -112,7 +112,7 @@ public long getRecurrencePeriod() { Calendar nextExecution = tab.ceil(now.getTimeInMillis()); long period = nextExecution.getTimeInMillis() - now.getTimeInMillis(); if(nextExecution.getTimeInMillis() - now.getTimeInMillis() <= 60000) { - period = period + 60_000L; // add one minute to not shedule it during one minute one than once + period = period + 60_000L; // add one minute to not schedule it during one minute one than once } return period; } catch (Exception ex) { diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index 688a20dd..f1589178 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -108,22 +108,22 @@ public static String formatTimeInMilisec(long time) { } long inMinutes = time / 60000; long hours = inMinutes / 60; - String formatedTime = ""; + String formattedTime = ""; if(hours > 0) { String unit = hours > 1 ? "hours" : "hour"; - formatedTime = hours + " " + unit; + formattedTime = hours + " " + unit; } long minutes = inMinutes - hours * 60; if(minutes > 0) { String unit = minutes > 1 ? "minutes" : "minute"; - formatedTime = formatedTime + " " + minutes + " " + unit; + formattedTime = formattedTime + " " + minutes + " " + unit; } long seconds = (time / 1000) - minutes * 60 - hours * 60 * 60; if(seconds > 0) { String unit = minutes > 1 ? "seconds" : "second"; - formatedTime = formatedTime + " " + seconds + " " + unit; + formattedTime = formattedTime + " " + seconds + " " + unit; } - return formatedTime; + return formattedTime; } public static void sendEmail(String subject, String message) throws MessagingException { @@ -131,7 +131,7 @@ public static void sendEmail(String subject, String message) throws MessagingExc DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); String address = plugin.getConfiguration().getEmailAddress(); if(address == null || address.isEmpty()) { - Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "e-mail addres is not set for notification about exceed disk size. Please set it in global configuration."); + Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "e-mail address is not set for notification about exceed disk size. Please set it in global configuration."); return; } MimeMessage msg = new MimeMessage(Mailer.descriptor().createSession()); @@ -161,7 +161,7 @@ public static void controlAllJobsExceedSize() throws IOException { Long exceedJobsSize = plugin.getConfiguration().getAllJobsExceedSize(); if(allJobsSize > exceedJobsSize) { try { - sendEmail("Jobs exeed size", "Jobs exceed size " + getSizeString(exceedJobsSize) + ". Their size is now " + getSizeString(allJobsSize)); + sendEmail("Jobs exceed size", "Jobs exceed size " + getSizeString(exceedJobsSize) + ". Their size is now " + getSizeString(allJobsSize)); } catch (MessagingException ex) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage plugin can not send notification about exceeting build size.", ex); } diff --git a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java index 031bdb58..22fb1680 100644 --- a/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/project/DiskUsagePostBuildCalculation.java @@ -46,7 +46,7 @@ public static class DescriptorImpl extends BuildStepDescriptor { @NonNull @Override public String getDisplayName() { - return "Calcualete disk usage of build"; + return "Calculate disk usage of build"; } @Override diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly index dbaa85da..bd98b8c5 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly @@ -2,7 +2,7 @@ - + diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index cf351f4e..3fdb7369 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -23,7 +23,7 @@ public class DiskUsageCalculationTest { /** - * Depends on test testReschedule() - if testReshedule fails this test probably will fail too. + * Depends on test testReschedule() - if testReschedule fails this test probably will fail too. * * see @testReschedule() */ @@ -32,7 +32,7 @@ public void testScheduledExecutionTime() throws Exception { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); - // attribut currentTask should have value calculation + // attribute currentTask should have value calculation TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *"); if(calculation.getLastTask() != null) { // should not be any, but if cancel; @@ -76,7 +76,7 @@ public void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation("0 " + hour + " * * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals("Disk usage calculaion should be executed accurately in 2 hours.", expectedPeriod, period, 60000); + assertEquals("Disk usage calculation should be executed accurately in 2 hours.", expectedPeriod, period, 60000); // for days calendar = new GregorianCalendar(); @@ -85,7 +85,7 @@ public void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals("Disk usage calculaion should be executed accurately in 2 days.", expectedPeriod, period, 60000); + assertEquals("Disk usage calculation should be executed accurately in 2 days.", expectedPeriod, period, 60000); // for months calendar = new GregorianCalendar(); @@ -95,7 +95,7 @@ public void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); + assertEquals("Disk usage calculation should be executed accurately in 2 months.", expectedPeriod, period, 60000); // day of week calendar = new GregorianCalendar(); @@ -105,13 +105,13 @@ public void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals("Disk usage calculaion should be executed accurately in 2 months.", expectedPeriod, period, 60000); + assertEquals("Disk usage calculation should be executed accurately in 2 months.", expectedPeriod, period, 60000); } /** - * Depends on test testScheduledExecutionTime() - if testReshedule fails this test probably will fail too. + * Depends on test testScheduledExecutionTime() - if testReschedule fails this test probably will fail too. *

    * see @testScheduledExecutionTime() */ @@ -120,7 +120,7 @@ public void testReschedule() throws Exception { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); - // attribut currentTask should have value calculation + // attribute currentTask should have value calculation TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation(minute + " * * * *").getNewInstance(); Timer.get().schedule(calculation, calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); // schedule it; calendar.add(Calendar.MINUTE, 10); @@ -134,7 +134,7 @@ public void testReschedule() throws Exception { @Test public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { - // attribut currentTask should have value calculation + // attribute currentTask should have value calculation List scheduledInstances = new ArrayList<>(); TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *").getNewInstance(); TestDiskUsageCalculation.startLoadInstancesHistory(scheduledInstances); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index e0f9f4d1..8b82aa1b 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -68,11 +68,11 @@ private List readFileList(File file) throws FileNotFoundException, IOExcep } private Long getSize(List files) { - long lenght = 0L; + long length = 0L; for(File file: files) { - lenght += file.length(); + length += file.length(); } - return lenght; + return length; } @Test @@ -215,17 +215,18 @@ public void save() { @Test public void testDoNotCalculateExcludedJobs() throws Exception { - FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); - FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); + FreeStyleProject excludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); + FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "includedJob"); List excludes = new ArrayList<>(); - excludes.add(exludedJob.getName()); + excludes.add(excludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); - j.buildAndAssertSuccess(exludedJob); + j.buildAndAssertSuccess(excludedJob); j.buildAndAssertSuccess(includedJob); BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - assertEquals("Disk usage for excluded project should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(exludedJob.getLastBuild()).getAllDiskUsage(), 0); + assertEquals("Disk usage for excluded project should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction( + excludedJob.getLastBuild()).getAllDiskUsage(), 0); assertTrue("Disk usage for excluded project should not be counted.", DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage() > 0); excludes.clear(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 8ef0fc52..a9738387 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -128,13 +128,13 @@ public void testCheckWorkspaces() throws Exception { Set nodes = prop.getAgentWorkspaceUsage().keySet(); assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( agent2.getNodeName())); - assertFalse("DiskUsage property should not contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace withour reference from project is not set.", nodes.contains( + assertFalse("DiskUsage property should not contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is not set.", nodes.contains( agent1.getNodeName())); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(true); prop.checkWorkspaces(); assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( agent2.getNodeName())); - assertTrue("DiskUsage property should contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace withour reference from project is set.", nodes.contains( + assertTrue("DiskUsage property should contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is set.", nodes.contains( agent1.getNodeName())); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(false); } @@ -193,7 +193,7 @@ public void testcheckWorkspacesIfAgentIsDeleted() throws Exception { } @Test - public void testchcekWorkspacesIfDoesNotExistsIsDeleted() throws Exception { + public void testCheckWorkspacesIfDoesNotExistsIsDeleted() throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); @@ -291,7 +291,7 @@ public void testBackwadrCompatibility2() throws IOException { property.getDiskUsage().loadAllBuilds(); assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); assertEquals("Size of workspaces should be loaded from previous configuration.", 4096L, property.getAllWorkspaceSize(), 0); - assertTrue("Path of workspace shoudl be loaded form previous configuration.", property.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + assertTrue("Path of workspace should be loaded form previous configuration.", property.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); } @Test diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java index 07ec45f0..78a9f20a 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageTestUtil.java @@ -43,11 +43,11 @@ protected static List readFileList(File file) throws FileNotFoundException } protected static Long getSize(List files) { - long lenght = 0L; + long length = 0L; for(File file: files) { - lenght += file.length(); + length += file.length(); } - return lenght; + return length; } protected static Slave createAgent(String name, String remoteFS, Jenkins jenkins, ComputerLauncher launcher) throws Exception { diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 3d73f468..1ec00ae7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -181,7 +181,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - // next build - configuration are builded on next agent + // next build - configuration are built on next agent // test if not active configuration are find and right counted // test if works with more complex configurations j.buildAndAssertSuccess(project1); @@ -207,7 +207,7 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - // matrix project is builded on the next agent + // matrix project is built on the next agent // test if new folder on agent2 is counted too project1.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 25e18612..48ac5efc 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -133,10 +133,11 @@ public void testMatrixProject() throws IOException, InterruptedException { } } + @Test public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); DiskUsageTestUtil.cancelCalculation(calculation); - FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, j.contextPath); + FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "freestyle1"); final JobWithoutBuildsDiskUsageCalculation testCalculation = new JobWithoutBuildsDiskUsageCalculation(); Thread t = new Thread(testCalculation.getThreadName()){ @Override @@ -155,6 +156,7 @@ public void run() { t.interrupt(); } + @Test public void testDoNotCalculateUnenabledDiskUsage() throws Exception { FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); DiskUsageProjectActionFactory.DESCRIPTOR.disableJobsDiskUsageCalculation(); @@ -170,13 +172,13 @@ public void testDoNotCalculateExcludedJobs() throws Exception { if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); } - FreeStyleProject exludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); - FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "incudedJob"); + FreeStyleProject excludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); + FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "includedJob"); List excludes = new ArrayList<>(); - excludes.add(exludedJob.getName()); + excludes.add(excludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for excluded project should not be counted.", 0, exludedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0); + assertEquals("Disk usage for excluded project should not be counted.", 0, excludedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0); assertTrue("Disk usage for included project should be not be counted.", includedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds() > 0); excludes.clear(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index c5afc766..bbca8b67 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -275,7 +275,7 @@ public void testDoNotCalculateExcludedJobs() throws Exception { DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); FreeStyleProject excludedJob = j.getInstance().createProject(FreeStyleProject.class, "excludedJob"); - FreeStyleProject includedJob = j.getInstance().createProject(FreeStyleProject.class, "incudedJob"); + FreeStyleProject includedJob = j.getInstance().createProject(FreeStyleProject.class, "includedJob"); if(Functions.isWindows()) { excludedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); includedJob.getBuildersList().add(new BatchFile("echo ahoj > log.log")); From c503734dec8e2f2ea6eb88e05298b41ebfd19793 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 19 Mar 2023 00:49:43 +0000 Subject: [PATCH 093/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f531abd0..f5cf3267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - [Replaces deprecated perform method in DiskUsagePostBuildCalculation](https://github.com/jenkinsci/disk-usage-plugin/pull/82) - [Removes deprecated DiskUsage and inline fields into child DiskUsageRecord](https://github.com/jenkinsci/disk-usage-plugin/pull/83) - [Removes unused class ProjectConfigListener](https://github.com/jenkinsci/disk-usage-plugin/pull/84) +- [Fix spelling errors](https://github.com/jenkinsci/disk-usage-plugin/pull/85) ### Release 0.28 (Oct 01, 2015) From b29c4e6217f08a5560ddfa3f1b558a212fd7e863 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 29 May 2023 16:30:06 +0100 Subject: [PATCH 094/158] [maven-release-plugin] prepare release disk-usage-1.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 560470c1..f4fedfe3 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 0.29-SNAPSHOT + 1.0 https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - HEAD + disk-usage-1.0 From fca8d73a0a45f4877b126405849495fc9eaf0e17 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 29 May 2023 16:30:10 +0100 Subject: [PATCH 095/158] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f4fedfe3..1e33f5b8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.0 + 1.1-SNAPSHOT https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - disk-usage-1.0 + HEAD From 303cb96573a93e0cea3d9c7dc0de09d228ad5a7c Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 4 Jun 2023 23:27:20 +0100 Subject: [PATCH 096/158] Fixes javadoc errors with java 18 --- .../plugins/disk_usage/DiskUsageProjectActionFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 4680b5ad..2a440a51 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -22,7 +22,7 @@ import org.kohsuke.stapler.StaplerRequest; /** - * @author: Nicolas De Loof + * @author Nicolas De Loof */ @Extension public class DiskUsageProjectActionFactory extends TransientProjectActionFactory implements Describable { From 118ad61cee4b1e155437dc2e3f245e8af91f8658 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 4 Jun 2023 23:30:00 +0100 Subject: [PATCH 097/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5cf3267..fff1d689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes +### Release 1.0 (2023-06-04) + - [Upgrades latest parent pom 4.53 and to Jenkins 2.361](https://github.com/jenkinsci/disk-usage-plugin/pull/55) - [Openrewrite code cleanup](https://github.com/jenkinsci/disk-usage-plugin/pull/57) - [Clean code using openrewrite CommonStaticAnalysis recipe](https://github.com/jenkinsci/disk-usage-plugin/pull/58) From 7c087043d6c5950eb474734ab32619e20eb0bbab Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 4 Jun 2023 23:50:34 +0100 Subject: [PATCH 098/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fff1d689..e0b0d1a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes + - [Fixes javadoc errors with java 18](https://github.com/jenkinsci/disk-usage-plugin/pull/87) + ### Release 1.0 (2023-06-04) - [Upgrades latest parent pom 4.53 and to Jenkins 2.361](https://github.com/jenkinsci/disk-usage-plugin/pull/55) From b578b9bac5039400bf60b8b162b19b2a78f718b5 Mon Sep 17 00:00:00 2001 From: Markus Winter Date: Thu, 29 Jun 2023 15:07:38 +0200 Subject: [PATCH 099/158] update styling - on the configure page where some old unstyled inputs and selects. Those are now jenkins styled - on the disk-usage overview page, the filter form is now styled like Jenkins forms with a corerspondingly styled button - made the svg a symbol (requires Jenkins 2.401.1 as previous lts versions filter out the ids and thus break the svg) --- pom.xml | 44 ++-- .../disk_usage/DiskUsageManagement.java | 3 +- .../DiskUsagePlugin/calculation.properties | 0 .../disk_usage/DiskUsagePlugin/index.jelly | 52 ++-- .../DiskUsagePlugin/index_ja.properties | 0 .../global.jelly | 241 ++++++++++-------- .../floatingBox_fr.properties | 0 .../ProjectDiskUsageAction/jobMain.jelly | 2 +- .../hudson/plugins/disk_usage/styles.css | 38 +++ .../images/symbols}/disk-usage.svg | 1 + 10 files changed, 218 insertions(+), 163 deletions(-) mode change 100755 => 100644 src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.properties mode change 100755 => 100644 src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index_ja.properties rename src/main/resources/hudson/plugins/disk_usage/{DiskUsageAction => ProjectDiskUsageAction}/floatingBox_fr.properties (100%) create mode 100644 src/main/resources/hudson/plugins/disk_usage/styles.css rename src/main/{webapp/icons => resources/images/symbols}/disk-usage.svg (99%) diff --git a/pom.xml b/pom.xml index 1e33f5b8..eae1ea40 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.54 + 4.66 disk-usage @@ -27,56 +27,46 @@ HEAD + + 2.401.1 + + + + + + io.jenkins.tools.bom + bom-2.401.x + 2198.v39c76fc308ca + pom + import + + + org.jenkins-ci.plugins mailer - 435.v79ef3972b_5c7 org.jenkins-ci.plugins matrix-project - 1.0 org.jenkins-ci.plugins junit - 1.20 io.jenkins.plugins jakarta-mail-api - 2.0.1-2 org.jenkins-ci.plugins promoted-builds - 3.0 + 892.vd6219fc0a_efb test - - - - - - maven-surefire-plugin - 3.0.0-M4 - - - - hudson.udp - -1 - - - false - 2 - - - - - repo.jenkins-ci.org diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java index 356a2f5d..9b52eb51 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageManagement.java @@ -25,7 +25,7 @@ public class DiskUsageManagement extends ManagementLink implements RootAction { @Override public String getIconFileName() { - return "/plugin/disk-usage/icons/disk-usage.svg"; + return "symbol-disk-usage plugin-disk-usage"; } @Override @@ -52,5 +52,4 @@ public Category getCategory() { public void doIndex(StaplerRequest req, StaplerResponse res) throws ServletException, IOException { res.sendRedirect(Jenkins.get().getRootUrlFromRequest() + "plugin/disk-usage"); } - } diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.properties b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/calculation.properties old mode 100755 new mode 100644 diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly index 985ad5eb..5b449d2c 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index.jelly @@ -1,14 +1,9 @@ - - - - - - - - + + +

    @@ -20,7 +15,7 @@
    -

    ${%Disk usage}

    +

    ${%Disk usage}

    • ${%Jobs}:${it.getDiskUsageInString(it.getCashedGlobalJobsDiskUsage())}
    • @@ -33,27 +28,32 @@ - -
      - ${%Builds older than } + +
      +
      ${%Builds older than }
      + - -
      -
      - ${%Builds younger than } +
      + +
      +
      +
      ${%Builds younger than }
      + - +
      + +
      - +
      diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index_ja.properties b/src/main/resources/hudson/plugins/disk_usage/DiskUsagePlugin/index_ja.properties old mode 100755 new mode 100644 diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly index bd98b8c5..d96042bc 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly @@ -1,113 +1,140 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + B + KiB + MiB + GiB + TiB - - - - - - - + B + KiB + MiB + GiB + TiB - - - - - - - + B + KiB + MiB + GiB + TiB - - - - - - - + B + KiB + MiB + GiB + TiB - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageAction/floatingBox_fr.properties b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox_fr.properties similarity index 100% rename from src/main/resources/hudson/plugins/disk_usage/DiskUsageAction/floatingBox_fr.properties rename to src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/floatingBox_fr.properties diff --git a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly index 3d64cc7d..430db4ff 100644 --- a/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/ProjectDiskUsageAction/jobMain.jelly @@ -2,7 +2,7 @@ - + ${it.displayName}
      diff --git a/src/main/resources/hudson/plugins/disk_usage/styles.css b/src/main/resources/hudson/plugins/disk_usage/styles.css new file mode 100644 index 00000000..17e1a22d --- /dev/null +++ b/src/main/resources/hudson/plugins/disk_usage/styles.css @@ -0,0 +1,38 @@ +.dup-input { + display: flex; +} + +.dup-input div.jenkins-select { + margin-left: 5px; + max-width: 65px; +} + +.dup-filter { + display: flex; + width: 360px; + align-items: center; + margin-bottom: 15px; + flex-wrap: wrap; + row-gap: 0.3rem; +} + +.dup-filter__label { + margin-right: 5px; + flex-basis: 38%; + margin-bottom: 0; + font-weight: var(--form-label-font-weight); +} + +.dup-filter__break { + flex-basis: 100%; +} + +.dup-filter input[type="number"]{ + width: 80px; +} + +.dup-filter div.jenkins-select { + margin-left: 5px; + min-width: 125px; + width: initial; +} \ No newline at end of file diff --git a/src/main/webapp/icons/disk-usage.svg b/src/main/resources/images/symbols/disk-usage.svg similarity index 99% rename from src/main/webapp/icons/disk-usage.svg rename to src/main/resources/images/symbols/disk-usage.svg index 8a7e704f..a1f00886 100644 --- a/src/main/webapp/icons/disk-usage.svg +++ b/src/main/resources/images/symbols/disk-usage.svg @@ -16,6 +16,7 @@ id="svg13684" height="48.000000px" width="48.000000px" + viewBox="0 0 48 48" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:export-filename="/dat/hudson/source/trunk/plugins/disk-usage/src/main/webapp/icons/48x48/disk-usage.png" inkscape:export-xdpi="90" From 56d4b19e54457d79bccd3f43bf4b6ba70944855e Mon Sep 17 00:00:00 2001 From: Markus Winter Date: Thu, 29 Jun 2023 16:24:25 +0200 Subject: [PATCH 100/158] use matrix 1.0 potentially newer matrix requires an update of the fileList files --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index eae1ea40..825e19d0 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,7 @@ org.jenkins-ci.plugins matrix-project + 1.0 org.jenkins-ci.plugins From bc54f558b2431345e5d53a21b1e7d680f485e4b2 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 3 Jul 2023 21:14:36 +0100 Subject: [PATCH 101/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b0d1a9..60f06eda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Upcoming changes - [Fixes javadoc errors with java 18](https://github.com/jenkinsci/disk-usage-plugin/pull/87) + - [update styling](https://github.com/jenkinsci/disk-usage-plugin/pull/88) ### Release 1.0 (2023-06-04) From 89d23dd714ca78c6f9034cb040e723da8661af19 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 3 Jul 2023 21:24:38 +0100 Subject: [PATCH 102/158] [maven-release-plugin] prepare release disk-usage-1.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 825e19d0..3164349d 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.1-SNAPSHOT + 1.1 https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - HEAD + disk-usage-1.1 From a944b9a4e3cbd4ef40ebc8f3df325b3392cb591e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 3 Jul 2023 21:24:43 +0100 Subject: [PATCH 103/158] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3164349d..a030f965 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.1 + 1.2-SNAPSHOT https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - disk-usage-1.1 + HEAD From 80b98f551be1cc1cb2502bccea3cfec6180506d2 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 3 Jul 2023 21:44:46 +0100 Subject: [PATCH 104/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f06eda..f36a2266 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes +### Release 1.1 (2023-07-03) + - [Fixes javadoc errors with java 18](https://github.com/jenkinsci/disk-usage-plugin/pull/87) - [update styling](https://github.com/jenkinsci/disk-usage-plugin/pull/88) From dfd321ae4b3d2fc43b42c0ce065e74a8237c445d Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Fri, 4 Aug 2023 23:13:13 +0000 Subject: [PATCH 105/158] Modernize to Jenkins 2.375.4 Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.jenkins.ModernizePlugin Co-authored-by: Moderne --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a030f965..f58f7e44 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.66 + 4.71 disk-usage From 08fe6e7ddd89810d2d4dac20bc2444508b4df82d Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Fri, 4 Aug 2023 19:50:47 -0700 Subject: [PATCH 106/158] SpotBugs fix: nullness issues --- .../BuildDiskUsageCalculationThread.java | 11 +++++- .../DiskUsageOvearallGraphGenerator.java | 3 ++ .../plugins/disk_usage/DiskUsageProperty.java | 15 ++++++-- .../plugins/disk_usage/DiskUsageUtil.java | 37 +++++++++++++++---- .../JobWithoutBuildsDiskUsageCalculation.java | 11 +++++- .../plugins/disk_usage/ProjectDiskUsage.java | 28 ++++++++++---- .../disk_usage/ProjectDiskUsageAction.java | 6 ++- .../WorkspaceDiskUsageCalculationThread.java | 8 +++- ...rkspaceDiskUsageCalculationThreadTest.java | 3 +- 9 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index bb33b2b5..5c0a33a6 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -72,6 +72,9 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } else { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } if(plugin.getConfiguration().isCalculationBuildsEnabled()) { logger.log(Level.FINER, "Calculation of builds is already in progress."); } @@ -83,7 +86,11 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForBuilds(); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return null; + } + String cron = plugin.getConfiguration().getCountIntervalForBuilds(); return new CronTab(cron); } @@ -106,7 +113,7 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationBuildsEnabled()) { + if(plugin == null || !plugin.getConfiguration().isCalculationBuildsEnabled()) { return false; } return !isExecutingMoreThenOneTimes(); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index 18220bd5..be74dd86 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -27,6 +27,9 @@ public long getRecurrencePeriod() { @Override protected void doRun() throws Exception { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } plugin.refreshGlobalInformation(); File jobsDir = new File(Jenkins.get().getRootDir(), "jobs"); Long freeJobsDirSpace = jobsDir.getTotalSpace(); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java index 02895200..44c6da32 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProperty.java @@ -1,5 +1,6 @@ package hudson.plugins.disk_usage; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.FilePath; import hudson.init.InitMilestone; @@ -7,6 +8,7 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; +import hudson.model.Computer; import hudson.model.Descriptor; import hudson.model.Hudson; import hudson.model.Item; @@ -201,7 +203,7 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size) { putAgentWorkspaceSize(node, path, size); } - public void putAgentWorkspaceSize(Node node, String path, Long size) { + public void putAgentWorkspaceSize(@NonNull Node node, String path, Long size) { Map workspacesInfo = getAgentWorkspaceUsage().get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); @@ -298,9 +300,14 @@ public void checkWorkspaces(boolean force) { checkLoadedBuilds(); } // only if it is wanted - can cost a quite long time to do it for all - if(Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCheckWorkspaceOnAgent() && owner instanceof TopLevelItem) { + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } + if(plugin.getConfiguration().getCheckWorkspaceOnAgent() && owner instanceof TopLevelItem) { for(Node node: Jenkins.get().getNodes()) { - if(node.toComputer() != null && node.toComputer().isOnline()) { + Computer computer = node.toComputer(); + if(computer != null && computer.isOnline()) { FilePath path = null; try { path = node.getWorkspaceFor((TopLevelItem) owner); @@ -337,7 +344,7 @@ public void checkWorkspaces(boolean force) { String path = pathIterator.next(); try { FilePath workspace = node.createPath(path); - if(!workspace.exists()) { + if(workspace != null && !workspace.exists()) { pathIterator.remove(); } } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java index f1589178..75f8f27d 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageUtil.java @@ -4,10 +4,12 @@ */ package hudson.plugins.disk_usage; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.FilePath; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; +import hudson.model.Computer; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Node; @@ -129,6 +131,9 @@ public static String formatTimeInMilisec(long time) { public static void sendEmail(String subject, String message) throws MessagingException { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } String address = plugin.getConfiguration().getEmailAddress(); if(address == null || address.isEmpty()) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "e-mail address is not set for notification about exceed disk size. Please set it in global configuration."); @@ -156,6 +161,9 @@ public static Long getSizeInBytes(String stringSize) { public static void controlAllJobsExceedSize() throws IOException { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } plugin.refreshGlobalInformation(); Long allJobsSize = plugin.getCashedGlobalJobsDiskUsage(); Long exceedJobsSize = plugin.getConfiguration().getAllJobsExceedSize(); @@ -248,6 +256,7 @@ public static int getIndex(String unit) { return index; } + @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") public static String getUnitString(int floor) { String unit = ""; switch (floor) { @@ -294,10 +303,15 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener DiskUsageUtil.addProperty(build.getProject()); property = (DiskUsageProperty) build.getProject().getProperty(DiskUsageProperty.class); } - if(build.getWorkspace() != null) { + FilePath workspace = build.getWorkspace(); + if(workspace != null) { ArrayList exceededFiles = new ArrayList<>(); AbstractProject project = build.getProject(); Node node = build.getBuiltOn(); + if (node == null) { + listener.getLogger().println("Node no longer available for disk usage calculation."); + return; + } if(project instanceof ItemGroup) { List projects = DiskUsageUtil.getAllProjects((ItemGroup) project); for(AbstractProject p: projects) { @@ -318,9 +332,9 @@ public static void calculationDiskUsageOfBuild(AbstractBuild build, TaskListener property.checkWorkspaces(); listener.getLogger().println("Started calculate disk usage of workspace"); Long startTimeOfWorkspaceCalculation = System.currentTimeMillis(); - Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(build.getWorkspace(), exceededFiles); + Long size = DiskUsageUtil.calculateWorkspaceDiskUsageForPath(workspace, exceededFiles); listener.getLogger().println("Finished Calculation of disk usage of workspace in " + DiskUsageUtil.formatTimeInMilisec(System.currentTimeMillis() - startTimeOfWorkspaceCalculation)); - property.putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), size); + property.putAgentWorkspaceSize(node, workspace.getRemote(), size); property.saveDiskUsage(); DiskUsageUtil.controlWorkspaceExceedSize(project); property.saveDiskUsage(); @@ -365,6 +379,9 @@ public static void calculateDiskUsageForProject(AbstractProject project) throws return; } DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } List exceededFiles = new ArrayList<>(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); if(property == null) { @@ -407,6 +424,9 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr return; } DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } // Build disk usage has to be always recalculated to be kept up-to-date // - artifacts might be kept only for the last build and users sometimes delete files manually as well. long buildSize = DiskUsageUtil.getFileSize(new File(Jenkins.get().getBuildDirFor(project), buildId), new ArrayList<>()); @@ -439,7 +459,7 @@ public static void calculateDiskUsageForBuild(String buildId, AbstractProject pr // should not happen AbstractBuild newLoadedBuild = (AbstractBuild) project._getRuns().getById(buildId); information = new DiskUsageBuildInformation(buildId, newLoadedBuild.getTimeInMillis(), newLoadedBuild.getNumber(), buildSize); - property.getDiskUsage().addBuildInformation(information, build); + property.getDiskUsage().addBuildInformation(information, null); } } property.saveDiskUsage(); @@ -457,7 +477,9 @@ public static Long calculateWorkspaceDiskUsageForPath(FilePath workspace, ArrayL Long diskUsage = 0L; if(workspace.exists()) { try { - diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getTimeoutWorkspace(), TimeUnit.MINUTES); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + int minutes = plugin == null ? 5 : plugin.getConfiguration().getTimeoutWorkspace(); + diskUsage = workspace.getChannel().callAsync(new DiskUsageCallable(workspace, exceeded)).get(minutes, TimeUnit.MINUTES); } catch (Exception e) { Logger.getLogger(DiskUsageUtil.class.getName()).log(Level.WARNING, "Disk usage fails to calculate workspace for file path " + workspace.getRemote() + " through channel " + workspace.getChannel(), e); @@ -490,11 +512,12 @@ public static void calculateWorkspaceDiskUsage(AbstractProject project) throws I continue; } - if(node.toComputer() != null && node.toComputer().getChannel() != null) { + Computer computer = node.toComputer(); + if(computer != null && computer.getChannel() != null) { Iterator iterator = property.getAgentWorkspaceUsage().get(nodeName).keySet().iterator(); while(iterator.hasNext()) { String projectWorkspace = iterator.next(); - FilePath workspace = new FilePath(node.toComputer().getChannel(), projectWorkspace); + FilePath workspace = new FilePath(computer.getChannel(), projectWorkspace); if(workspace.exists()) { Long diskUsage = property.getAgentWorkspaceUsage().get(node.getNodeName()).get(workspace.getRemote()); ArrayList exceededFiles = new ArrayList<>(); diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index b9734199..92635faf 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -36,6 +36,9 @@ public JobWithoutBuildsDiskUsageCalculation() { @Override public void execute(TaskListener listener) throws IOException, InterruptedException { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return; + } if(!isCancelled() && startExecution()) { try { ItemGroup itemGroup = Jenkins.get(); @@ -87,7 +90,11 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForJobs(); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return null; + } + String cron = plugin.getConfiguration().getCountIntervalForJobs(); return new CronTab(cron); } @@ -98,7 +105,7 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationJobsEnabled()) { + if(plugin == null || !plugin.getConfiguration().isCalculationJobsEnabled()) { return false; } return !isExecutingMoreThenOneTimes(); diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java index f6b2a8a7..05c0364e 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsage.java @@ -5,7 +5,10 @@ package hudson.plugins.disk_usage; import com.google.common.collect.Maps; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import hudson.BulkChange; +import hudson.FilePath; import hudson.XmlFile; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -97,7 +100,11 @@ private int numberOfBuildFolders() throws IOException { File file = job.getBuildDir(); int count = 0; if(file != null && file.exists() && file.isDirectory()) { - for(File f: file.listFiles()) { + File[] files = file.listFiles(); + if (files == null) { + return count; + } + for(File f: files) { if(!FileUtils.isSymlink(f) && !f.isDirectory()) { count++; } @@ -111,7 +118,7 @@ public void putSlaveWorkspaceSize(Node node, String path, Long size) { putAgentWorkspaceSize(node, path, size); } - public void putAgentWorkspaceSize(Node node, String path, Long size) { + public void putAgentWorkspaceSize(@NonNull Node node, String path, Long size) { Map workspacesInfo = slaveWorkspacesUsage.get(node.getNodeName()); if(workspacesInfo == null) { workspacesInfo = new ConcurrentHashMap<>(); @@ -148,8 +155,10 @@ public void loadAllBuilds() throws IOException { continue; } AbstractBuild build = (AbstractBuild) run; - if(build.getWorkspace() != null) { - putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); + FilePath workspace = build.getWorkspace(); + Node node = build.getBuiltOn(); + if(workspace != null && node != null) { + putAgentWorkspaceSize(node, workspace.getRemote(), 0l); } DiskUsageBuildInformation information = new DiskUsageBuildInformation(build.getId(), build.getTimeInMillis(), build.number, 0l); addBuildInformation(information, build); @@ -182,11 +191,16 @@ public DiskUsageBuildInformation getDiskUsageBuildInformation(int number) { return null; } - public void addBuildInformation(DiskUsageBuildInformation info, AbstractBuild build) { + public void addBuildInformation(DiskUsageBuildInformation info, @Nullable AbstractBuild build) { if(!containsBuildWithId(info.getId())) { buildDiskUsage.add(info); - if(build != null && build.getWorkspace() != null) { - putAgentWorkspaceSize(build.getBuiltOn(), build.getWorkspace().getRemote(), 0l); + if (build == null) { + return; + } + FilePath workspace = build.getWorkspace(); + Node node = build.getBuiltOn(); + if(workspace != null && node != null) { + putAgentWorkspaceSize(node, workspace.getRemote(), 0l); } } } diff --git a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java index 3cfb3821..19cebe71 100644 --- a/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java +++ b/src/main/java/hudson/plugins/disk_usage/ProjectDiskUsageAction.java @@ -335,6 +335,10 @@ public Graph getGraph() throws IOException { /** Shortcut for the jelly view */ public boolean showGraph() { - return Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().isShowGraph(); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return false; + } + return plugin.getConfiguration().isShowGraph(); } } diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index ef197016..68737c7e 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -83,7 +83,11 @@ public AperiodicWork getNewInstance() { @Override public CronTab getCronTab() throws ANTLRException { - String cron = Jenkins.get().getPlugin(DiskUsagePlugin.class).getConfiguration().getCountIntervalForWorkspaces(); + DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); + if (plugin == null) { + return null; + } + String cron = plugin.getConfiguration().getCountIntervalForWorkspaces(); return new CronTab(cron); } @@ -94,7 +98,7 @@ public DiskUsageCalculation getLastTask() { private boolean startExecution() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); - if(!plugin.getConfiguration().isCalculationWorkspaceEnabled()) { + if(plugin == null || !plugin.getConfiguration().isCalculationWorkspaceEnabled()) { return false; } return !isExecutingMoreThenOneTimes(); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index bbca8b67..f188f182 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Functions; import hudson.matrix.AxisList; import hudson.matrix.MatrixProject; @@ -316,7 +317,7 @@ public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { public static class TestDiskUsageProperty extends DiskUsageProperty { @Override - public void putAgentWorkspaceSize(Node node, String path, Long size) { + public void putAgentWorkspaceSize(@NonNull Node node, String path, Long size) { LOGGER.fine("workspace size " + size); try { Thread.sleep(10000); // make this operation longer From bd6a41992712ca2428a825df3e7e51aef4c58f80 Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Fri, 4 Aug 2023 20:17:11 -0700 Subject: [PATCH 107/158] SpotBugs: fix or suppress static warnings --- .../disk_usage/BuildDiskUsageCalculationThread.java | 2 ++ .../plugins/disk_usage/DiskUsageBuildInformation.java | 7 +++---- .../disk_usage/DiskUsageOvearallGraphGenerator.java | 6 +++--- .../disk_usage/JobWithoutBuildsDiskUsageCalculation.java | 2 ++ .../disk_usage/WorkspaceDiskUsageCalculationThread.java | 2 ++ 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index 5c0a33a6..0c1596e5 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -1,6 +1,7 @@ package hudson.plugins.disk_usage; import antlr.ANTLRException; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -95,6 +96,7 @@ public CronTab getCronTab() throws ANTLRException { } @Override + @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") public AperiodicWork getNewInstance() { if(currentTask != null) { currentTask.cancel(); diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java index e9b72d0d..fcb9c738 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageBuildInformation.java @@ -5,7 +5,6 @@ package hudson.plugins.disk_usage; import java.io.Serializable; -import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Objects; @@ -16,9 +15,9 @@ */ public class DiskUsageBuildInformation implements Serializable, Comparable { - private static final long serialVersionUID = 1; + private static final long serialVersionUID = 8936406908101796594L; - private static final DateFormat LEGACY_ID_FORMATTER = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + private static final String PATTERN = "yyyy-MM-dd_HH-mm-ss"; private String id; private long timestamp; @@ -36,7 +35,7 @@ public DiskUsageBuildInformation(String id, long timestamp, int number, Long siz private Object readResolve() { if(timestamp == 0) { try { - timestamp = LEGACY_ID_FORMATTER.parse(id).getTime(); + timestamp = new SimpleDateFormat(PATTERN).parse(id).getTime(); } catch (ParseException x) { // never mind } diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java index be74dd86..6e8f3354 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageOvearallGraphGenerator.java @@ -39,7 +39,7 @@ protected void doRun() throws Exception { } public static class DiskUsageRecord { - private static final SimpleDateFormat sdf = new SimpleDateFormat("d/M"); + private static final String PATTERN = "d/M"; Date date; private Long jobsWithoutBuildsUsage = 0L; private Long allSpace = 0L; @@ -54,10 +54,10 @@ public DiskUsageRecord(Long diskUsageBuilds, Long diskUsageWorkspaces, Long disk this.allSpace = allSpace; this.diskUsageNonAgentWorkspaces = diskUsageNonAgentWorkspaces; date = new Date(){ - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 679659655161606365L; @Override public String toString() { - return sdf.format(this); + return new SimpleDateFormat(PATTERN).format(this); } }; } diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 92635faf..27a4f9ed 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -5,6 +5,7 @@ package hudson.plugins.disk_usage; import antlr.ANTLRException; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.AperiodicWork; @@ -77,6 +78,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } @Override + @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") public AperiodicWork getNewInstance() { if(currentTask != null) { currentTask.cancel(); diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 68737c7e..1e576935 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -5,6 +5,7 @@ package hudson.plugins.disk_usage; import antlr.ANTLRException; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.AperiodicWork; @@ -70,6 +71,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } @Override + @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") public AperiodicWork getNewInstance() { if(currentTask != null) { currentTask.cancel(); From fb1e46ed9a114931951a566021366e0cf488eb7d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 4 Sep 2023 22:57:16 +0100 Subject: [PATCH 108/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f36a2266..334614ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes + - [Modernize Tooling](https://github.com/jenkinsci/disk-usage-plugin/pull/89) + ### Release 1.1 (2023-07-03) - [Fixes javadoc errors with java 18](https://github.com/jenkinsci/disk-usage-plugin/pull/87) From fc9772d432acfdac223415aab7cafeaa532efc47 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 5 Sep 2023 19:50:52 +0100 Subject: [PATCH 109/158] Change deprecated method usage in test --- .../plugins/disk_usage/integration/DiskUsagePropertyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index a9738387..6230cd50 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -73,7 +73,7 @@ public void testCalculationWorkspaceForItemInNonTopLeverGroupItem() throws Excep j.buildAndAssertSuccess(project); DiskUsageProperty p = process.getProperty(DiskUsageProperty.class); Thread.sleep(1000); - p.getAllNonSlaveOrCustomWorkspaceSize(); + p.getAllNonAgentOrCustomWorkspaceSize(); } @Test From bb643a60d9ee0a19a77b6b1070410921354fc263 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 5 Sep 2023 19:53:25 +0100 Subject: [PATCH 110/158] Remove spotbugs configuration in Jenkinsfile This was needed when spotbugs issues were not yet fixed --- Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 274221ec..0ce3dbe4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,5 +5,4 @@ buildPlugin( [platform: 'linux', jdk: 17], [platform: 'windows', jdk: 11], ], - spotbugs: [ignoreQualityGate: true, ignoreFailedBuilds: false], ) From 43bc77dfb62a26d71d9b0044cc8162191bed9983 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 14:23:24 +0100 Subject: [PATCH 111/158] Move matrix plugin to test scope It being used only in test code Matrix plugin 1.5 compiles against a newer Jenkins and introduces a new file permalinks that should taken into account in fileList in each zip file. Matrix plugin 1.5 now corrects for JENKINS-13554 and deletes file and deleting a build. --- pom.xml | 2 +- .../ProjectDiskUsageActionTest.java | 15 +++++++++------ .../testCalculateDiskUsageForMatrixJob.zip | Bin 30806 -> 30799 bytes .../testMatrixProject.zip | Bin 31046 -> 31039 bytes 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index f58f7e44..d127172f 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ org.jenkins-ci.plugins matrix-project - 1.0 + test org.jenkins-ci.plugins diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 03763bc7..56c9f818 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -101,24 +101,27 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(sizeofBuild); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).setDiskUsage(sizeOfMatrixBuild1); DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).setDiskUsage(sizeOfMatrixBuild2); + long size1 = 5390; long size2 = 2390; int count = 1; long matrixBuild1TotalSize = sizeOfMatrixBuild1; - long matrixBuild2TotalSize = sizeOfMatrixBuild2; for(MatrixConfiguration c: matrixProject.getItems()) { - AbstractBuild configurationBuild = c.getBuildByNumber(1); + + final AbstractBuild configurationBuild = c.getBuildByNumber(1); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild).setDiskUsage(count * size1); matrixBuild1TotalSize += count * size1; - AbstractBuild configurationBuild2 = c.getBuildByNumber(2); + + final AbstractBuild configurationBuild2 = c.getBuildByNumber(2); DiskUsageTestUtil.getBuildDiskUsageAction(configurationBuild2).setDiskUsage(count * size2); - matrixBuild2TotalSize += count * size2; + count++; } + matrixBuild2.delete(); - Long matrixProjectBuildsTotalSize = matrixBuild1TotalSize + matrixBuild2TotalSize - sizeOfMatrixBuild2; + assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); + assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all").longValue()); } diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageForMatrixJob.zip b/src/test/resources/hudson/plugins/disk_usage/integration/DiskUsageUtilTest/testCalculateDiskUsageForMatrixJob.zip index c4bd1ebc220673fd5e89badc7d6c7a9c5ca64cd6..f038977b38288e1434580c26c2ed8e9f7f3d161f 100644 GIT binary patch delta 3441 zcmZ`*dr*|u7610`d%7^O*cMys(3`jl18z-7D!Hygoxy=ppA92+GY;FIFmLf}>WAFT`|)Ec zoS9<@J#;+bnxV5vrfK#6pk`4BqpN>XuW&L(*kM~>xsa4Y$FN7x2$ z#F5Z|+fMM>)B~ZB)LruDPoy8>W*gFvaX}%Y6rVQYn?8cZ&gi+ce?NFGXUj80yX&RMFEHAh;s(;)m2*P*t=MV&pl}`If=ZR`D=#H)UZt$qB`1SUGBzr%a{bZ)y zcD&m#5WMllzcv+ge!lJ7+q;)n{^{V_&MH;^(hYB2ytmN#Uh#*2T&dmtc9HKFdkxul z;ucrZNk4O8C z2%ng42i40w*&62f5l)%|#HGR!)i;b;AxT>l;dBqR&l5^{Y&oTm!-%Vd(l`OVdK)b3 z^*EuELn>)g6!whkQl6u5QJ6JyIkX#S+GsKT%IIbXPRF?#D?T^;fm2%2CSah}1Y=qu z&c=Qkt}BLF!@Tv-xrnP%BDG~fzA*-Qq5+cGfQ1!>)VaMp4$M~m@+c?9b!;tSNVAlF zlZVb39|EC$<~-HOw_9kuEa5wINp)9M)4)FLdKri2Jp{{ zpF&eN1GSa0xX~$+LjrDXoaRtvg|U3VGZ0{GcdGWBA1N#YK;TmY)|EO&ew^gJ%&Oq+^zGG+iW@=^Xh#h zEtXC_=&#S_@vH0*$q@z>;x)g-_m;MZ7S_@_F6p4CNgy9~J3 zoe6rjdGgu+Rpj2rj7jJI+#y@n@!Df47~U$WYB0VgABWf1kc;tD?!mHD6U@z-$g7LR zC{2A+0*76z%kiL9B=-{#Xx>H2opdO|SehO;m&``V29f+e0*Rbw%(eNG!mEPnNW0MsSahIWntKcAXtQ_W#^Lkxg!}S)wNWItskriEUY*?P#xT~tBU+Kn>StlxMDdYT>15+ftX(u$=@6G^ z!dlrtCfG0y2V2|>0-G!SjX5j zn@fAOCVI`$@}*s4FapJ4a76*G_(hUDhii>%!70HVH#Sr!DH!^Ig%Hy5HG?!})Xsj5on%t*OMnod*CUR1mDn*hskMAg{ zi3aPEQG|C{Ea{X*_l#3;eQ_#Sklvclwa?WA$XD`IyDaL=p#}2k^zkA3ePlGceB@_T z@)2*bqVdR|&s`plK)I2c;%&8VVOUd)aEJwEG=iG=Q-$67%>j{=l_+K-YLSz)mf^~xm7oPf zZkNHkVlA=x=n#(?uP!02^7QXb`RvwUJSJl@G`cc+Ur`#9j&i;!XwyW#jn~JR3_r8U iSM}aiBB`w4n$K+Ps&?76I#%5~=wItBK^UoEtN#JeW1&(2 delta 3331 zcmZ`*Yj9J?71mwLmLLI8Jbd*PLocVl$sH3fi{`amJR_z;73TOOi}Gs46G#;Yqay0i}$s}EvDY8qa8svO7XU5T!67Yq31!u9Ys zNeI>FV=8EbrMeCNS!vK`OZa;o!$e#wYQ?AO5=7~T!5aYVazm|u&-J=GEj;0 zm3;^~vM`xzz-t-zu`T}_sIxk8eU%pP>nC^;9u|10oe@20I4eX4Gam@3r3XqyjFpR- zg?65iDm$~Y5w@?RS@C0kP>aoZ%Xk1X*N77}i=s0|i@>9o9gMg>s7-pFNOVn(TZsB+ znaR;qeRMj1kIc@o9E#s@boLAE*yztJUl(Y^wa6^>(Wo!6Xrm7c2#Km~@hJP1=)Oy% z^1xG+jj^DHM%EF%WY@88U^?H4nI0WpES29j$KphI%j0?*oy|DL_>JoI)ZU`Tf^z$j zDK%c18;o|9cktsbR!c_(?UD0CO7f&=X3EC`94)43qi~){soOy$PZL|qtU zctYd~tY_MaeyZ+Zx!~Sosp(X|PwJY}<*k^s%i!@DaVlpCx|hh?8VSzUn5Qm!R{IN~ zHbigGQl~uPcxBaASsN(IbzI$`u?r3%VwUwMcbnajqI^Bo#ubeR+ zzNz_mUem1$xAiM;>u=olj~^JmG1Bv%cBjw%hkLI!f2;V|XL~O8Z}`ve4qoluC|yX! zJ@sr_4kk3a%J@4zat+31u+P=cWngnCihATSp(eL0iD1It=KHw>+nkr7UTemkrUAUy zUjf%HGkHOU_Fb!xIUtfL6;2P%!Z$l=&`(XLK+Sx7wcCp8Av+n9%@gwsu!bARZP|Qt z+Z;^!(hv@*ac;m&zDBsym^%a0-GzvRt>jn=g>3K_sqv*?Att&c*nA?nFT>Mab1|`2 z!iu0s_Nh5@f3O(WoAWRk7Ku8QLUZuRni>SQi)5p09@_3BZ^+BQd=bAMN*vpkMje_k zxjl~`d6SvN7^DGA4%^8_4L|NwjtT^3fiWFa87B zG=x`>G%erR6OLWlO1>vUKMpzgWq+lk3>#i*Es0+=H-kfWJz9j?XrRhvBQZD)o)KI8 z!lio3PF#45nPrf^>?KodxiWriFq0FWvWjNBPVJA*L zV<+udoET|T^OUn!yvB$!JUQA*3bQ$5ax|S*;9{KX7s>0{Sk}CVwqem=q7|o73H0yG za}Tmrc&oAiJ9fG8d7CJ7z__XaRqbBkhjdkem)pH0H5b)uoDe(8aB{Pm3^H>VCA}iK zE$>9KG^lunJ|vCA)-96GJnj(5(#pbaPJ^_;N`8}oPZ|su-OxaqXT_P{UJ-k5H7b{z z$z@Y~Yiv1tcL`-1MRL}xz=kBTTZwCS9FB?ob;|x@0*(ou9WrK7*hVgTpI;;oV~`0E zzgHN=(m)j*Ge)@RE$*gj6#ZL?-5U4x`(#&5W_pfdzq>wK^TJ7ShS=1wvpUaTVtizo(4Wzh;GybyHK!sa_$Xb!S z9D^2d0sm;7NIZ7VvYFE{Ia`fQt7wVRsx75kQ^{Kzga$4A0ZZ4@9#I_k3a)P@4-)3I zMV8b%?IJl|LRk)k0u@{r>QZiImS%G`F@5ZnAy1JO{|I==CowbQFk>%fS+Fs^ZY2 zP0PuMlP`B~cE=NMb#aJI?q_@K@zjpXaCnO&p3_=aK(M!gnC5ZD2ffQlR}EhVw#xC)5t8!H8Wp6JJf-C9DRuLi zZGxeNl_0A%33IpUQ_nm%&UZ>_sTCq+nKk8}!mL}C$mzlsbIRd`@(F`2a)VvB7*5|8 zr^#s-_R7mAr-`nPG7{6|JIqW>6H7h!Po5_G zWGJb6&S8nCi25BWiP z^05B=t_xQ^$nb-8$XIc`DV1O{~xV4-agIGXMYp diff --git a/src/test/resources/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest/testMatrixProject.zip b/src/test/resources/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest/testMatrixProject.zip index 3cdb91b3ff93816e7c2d07c659f74dc1b85190c8..8009c471860f3e821d103920f9a8aa34815e3313 100644 GIT binary patch delta 3303 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�}TvDBQC6U z<-hrk;l!trpXXQHy*jVoFt7h)-h1-c{!d1_{;c_4P2OMbzg78z^wWS>p+hU2~}8T)AYICIpfbY+1_`NTEouQnUUZ`!?FLdx?wbM%4oOh7?ga|lt3d#f5~ zd1g>2Ef#jOB6s6q1v{MC(O6db5eE8}!*(!vHks)aX{0?;u-!)JTk@c%k-ry! zVkSq5@U%}N8`PY1XJ|>2p9tv6YN1JlhBI`-LX**=7%71ki9(^If8QMavDls}io(hM z)SyO}wA`y}WF^-oPA5z{+?I7N2{RRd4M-khQ43)*^_)FBti{YgIT;U_8_8T?X@Feg z;79L`3X&bW?Oc$@OVBelb}q)a6lAgKsBJ0Wg4_*-qq(9i@jVADVI$EBw0V+o=75Ks zkui6`gRbxD;p~-2o&jeMwvgx8M*{vfT#SZMiTqWVEvqDd!eo3&$sIAARW@eF)My%+ z6Xu;!7MBTQW0Vog8B=5H$?pP7HA_%EO_0Zk&ngR1+NFnSrxbSFsKAHWHnbni!xsl7 za@UCNMk}t>m6O6ax^%!?3 zvJg*NnL`9}s%3edVkyn<9NipG3CES}e<6;wr||x`)L@_(saB6Z1_ zXetfq4;deJNaO~{Etsou8HGGF^9A_3S0X2bX&o#^?*@tJEPU5G80oJ7 zaqzng-cGY`f`{JIW2I)rc}gpe0gZI3s+RgMCTTIg#X~LxOf^e?^xAJ}VYMRU3OiIi_SnG10 z?bn1El^Gk%ww%Qoi>(?QX)Py*119aF|C{lJ06~YRZC<6r@2v}F-`Zv&kCq4F(Y74k z{Vav^*+E!8q{iEO(`c)TL{SzC)c*pDDQO`QD?`v+uw0xM(2qJBh}y+>^<8;97rzmv zrkl+cE-p#Q$AdPa2I<1>24!azj9ORx#kn2} zDb44s*Bu&=?H+Pon40B!9HHjD0=nDD#{hd)j;_LRZ9I}jS<{&KIGtrsVn`oZNQ#?7 z=c1#bYfr_i)fRG0K(p1Njs8$&A+|!snyeNYvRCHIB8sH=wX=}Q)znN6eN|=|Qo*lg z{4K@QwBp@?3NkI0t{7eLHIYmBt}8|p9Gqta^l?)d+Lax zlyBbJqYbo6dYy&*tdy#5LTgf>@@PaVsav~?U7Vv2- zuj7QSU9P~fG6t`P%*P2rarl)!&hu-D->h5i+QGO^;2R(l~|p%|@X HPv3t5bwyPN From 89687d9ac54065f48fea639ff2a4c9db014abecc Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 14:58:20 +0100 Subject: [PATCH 112/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 334614ba..cc97aa9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Upcoming changes - [Modernize Tooling](https://github.com/jenkinsci/disk-usage-plugin/pull/89) + - [Move matrix plugin to test scope](https://github.com/jenkinsci/disk-usage-plugin/pull/91) ### Release 1.1 (2023-07-03) From 75d67ede06ff1b78bb79d5a4720dd0a3216ad2ab Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 17:27:36 +0100 Subject: [PATCH 113/158] Removes usage of deprecated ANTLRException This is no longer being thrown by Crontab constructor https://github.com/jenkinsci/jenkins/pull/7293 --- .../BuildDiskUsageCalculationThread.java | 3 +-- .../disk_usage/DiskUsageCalculation.java | 24 +++++++------------ .../JobWithoutBuildsDiskUsageCalculation.java | 3 +-- .../WorkspaceDiskUsageCalculationThread.java | 3 +-- .../disk_usage/TestDiskUsageCalculation.java | 3 +-- 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java index 0c1596e5..4c8830a2 100644 --- a/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/BuildDiskUsageCalculationThread.java @@ -1,6 +1,5 @@ package hudson.plugins.disk_usage; -import antlr.ANTLRException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractBuild; @@ -86,7 +85,7 @@ public void execute(TaskListener listener) throws IOException, InterruptedExcept } @Override - public CronTab getCronTab() throws ANTLRException { + public CronTab getCronTab() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if (plugin == null) { return null; diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java index 1b7e3b33..41563ffc 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageCalculation.java @@ -4,7 +4,6 @@ */ package hudson.plugins.disk_usage; -import antlr.ANTLRException; import hudson.model.AsyncAperiodicWork; import hudson.scheduler.CronTab; import java.util.Calendar; @@ -13,7 +12,6 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import java.util.logging.Logger; import jenkins.util.Timer; /** @@ -56,20 +54,14 @@ public String getThreadName() { public abstract DiskUsageCalculation getLastTask(); public long scheduledLastInstanceExecutionTime() { - try { - if(getLastTask() == null || getLastTask().isCancelled()) { // not scheduled - return 0L; - } - long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); - if(time < new GregorianCalendar().getTimeInMillis()) { - return 0; - } - return time; - - } catch (ANTLRException ex) { - Logger.getLogger(DiskUsageCalculation.class.getName()).log(Level.SEVERE, null, ex); - return -1; + if(getLastTask() == null || getLastTask().isCancelled()) { // not scheduled + return 0L; + } + long time = getCronTab().ceil(new GregorianCalendar().getTimeInMillis()).getTimeInMillis(); + if(time < new GregorianCalendar().getTimeInMillis()) { + return 0; } + return time; } @Override @@ -102,7 +94,7 @@ public void reschedule() { Timer.get().schedule(getNewInstance(), getRecurrencePeriod(), TimeUnit.MILLISECONDS); } - public abstract CronTab getCronTab() throws ANTLRException; + public abstract CronTab getCronTab(); @Override public long getRecurrencePeriod() { diff --git a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java index 27a4f9ed..558c1089 100644 --- a/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java +++ b/src/main/java/hudson/plugins/disk_usage/JobWithoutBuildsDiskUsageCalculation.java @@ -4,7 +4,6 @@ */ package hudson.plugins.disk_usage; -import antlr.ANTLRException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractProject; @@ -91,7 +90,7 @@ public AperiodicWork getNewInstance() { } @Override - public CronTab getCronTab() throws ANTLRException { + public CronTab getCronTab() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if (plugin == null) { return null; diff --git a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java index 1e576935..5a76f6b7 100644 --- a/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java +++ b/src/main/java/hudson/plugins/disk_usage/WorkspaceDiskUsageCalculationThread.java @@ -4,7 +4,6 @@ */ package hudson.plugins.disk_usage; -import antlr.ANTLRException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.AbstractProject; @@ -84,7 +83,7 @@ public AperiodicWork getNewInstance() { } @Override - public CronTab getCronTab() throws ANTLRException { + public CronTab getCronTab() { DiskUsagePlugin plugin = Jenkins.get().getPlugin(DiskUsagePlugin.class); if (plugin == null) { return null; diff --git a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java index 1abcf8ef..805804f0 100644 --- a/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java +++ b/src/test/java/hudson/plugins/disk_usage/TestDiskUsageCalculation.java @@ -1,6 +1,5 @@ package hudson.plugins.disk_usage; -import antlr.ANTLRException; import hudson.model.AperiodicWork; import hudson.model.TaskListener; import hudson.scheduler.CronTab; @@ -36,7 +35,7 @@ public void setCron(String cron) { } @Override - public CronTab getCronTab() throws ANTLRException { + public CronTab getCronTab() { return new CronTab(cron); } From 9465f7ea8d65d061ab579cddb8a2632c8cb41dc7 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 17:44:20 +0100 Subject: [PATCH 114/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc97aa9a..5440f493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [Modernize Tooling](https://github.com/jenkinsci/disk-usage-plugin/pull/89) - [Move matrix plugin to test scope](https://github.com/jenkinsci/disk-usage-plugin/pull/91) + - [Removes usage of deprecated ANTLRException](https://github.com/jenkinsci/disk-usage-plugin/pull/92) ### Release 1.1 (2023-07-03) From 8b47e0102857264ebc47478cb2cab0626eb3418e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 18:15:36 +0100 Subject: [PATCH 115/158] [maven-release-plugin] prepare release disk-usage-1.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d127172f..28cabdd3 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.2-SNAPSHOT + 1.2 https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - HEAD + disk-usage-1.2 From 87c1c5c29d706d536e40a68e862d5b818a58c74b Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 18:15:40 +0100 Subject: [PATCH 116/158] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 28cabdd3..6f3108e2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.2 + 1.3-SNAPSHOT https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - disk-usage-1.2 + HEAD From e309a6ac552ff8fd32ac703a284eec11a2070cd3 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 6 Sep 2023 18:16:51 +0100 Subject: [PATCH 117/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5440f493..327d7a06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes +### Release 1.2 (2023-09-06) + - [Modernize Tooling](https://github.com/jenkinsci/disk-usage-plugin/pull/89) - [Move matrix plugin to test scope](https://github.com/jenkinsci/disk-usage-plugin/pull/91) - [Removes usage of deprecated ANTLRException](https://github.com/jenkinsci/disk-usage-plugin/pull/92) From 5e16b7ccff64fc9b08b383da5fe15021195af6a0 Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Wed, 20 Sep 2023 15:26:26 +0000 Subject: [PATCH 118/158] feat: rebaseline Jenkins to 2.387.3 Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.jenkins.ModernizePlugin Co-authored-by: Moderne --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f3108e2..342c1d74 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.71 + 4.73 disk-usage From 34ec924c46dfbe4ac238f70a61cad02a50931f1d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 20 Sep 2023 18:22:29 +0100 Subject: [PATCH 119/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 327d7a06..e933006b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes + - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) + ### Release 1.2 (2023-09-06) - [Modernize Tooling](https://github.com/jenkinsci/disk-usage-plugin/pull/89) From 8a31e0a02d809e2df6ef3c80c676e010b3f8a07f Mon Sep 17 00:00:00 2001 From: gounthar Date: Tue, 17 Oct 2023 18:52:00 +0200 Subject: [PATCH 120/158] Test with Java 21. --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0ce3dbe4..54e9032d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ buildPlugin( timeout: 30, useContainerAgent: true, configurations: [ - [platform: 'linux', jdk: 17], - [platform: 'windows', jdk: 11], + [platform: 'linux', jdk: 21], + [platform: 'windows', jdk: 17], ], ) From 4cdfe2d21325912f34c035bd1e523fbb6686fbcf Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 17 Oct 2023 21:43:02 +0100 Subject: [PATCH 121/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e933006b..886bc9a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Upcoming changes - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) + - [Test with Java 21.](https://github.com/jenkinsci/disk-usage-plugin/pull/94) ### Release 1.2 (2023-09-06) From 5eb9dc7dd2e6875a0ad0304e01310c2ec6512106 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 1 Apr 2024 18:19:40 +0100 Subject: [PATCH 122/158] Adds checks for user defined crontab entries --- .../DiskUsageProjectActionFactory.java | 28 +++++++++++++++++++ .../global.jelly | 6 ++-- .../plugins/disk_usage/Messages.properties | 1 + 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 2a440a51..633ab127 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -8,6 +8,7 @@ import hudson.model.Describable; import hudson.model.Descriptor; import hudson.model.TransientProjectActionFactory; +import hudson.scheduler.CronTab; import hudson.security.Permission; import java.util.ArrayList; import java.util.Collection; @@ -17,8 +18,11 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; + +import hudson.util.FormValidation; import jenkins.model.Jenkins; import net.sf.json.JSONObject; +import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; /** @@ -378,6 +382,30 @@ private void configureBuildsCalculation(JSONObject form) { } } + + private FormValidation checkCrons(String cron){ + try { + final CronTab cronTab = new CronTab(cron); + final String sanity = cronTab.checkSanity(); + if (sanity == null){ + return FormValidation.ok(); + } else { + return FormValidation.warning(sanity); + } + } catch (IllegalArgumentException e){ + return FormValidation.error(Messages.InvalidCrontab(cron)); + } + } + public FormValidation doCheckCountIntervalBuilds(@QueryParameter String value){ + return checkCrons(value); + } + public FormValidation doCheckCountIntervalJobs(@QueryParameter String value){ + return checkCrons(value); + } + public FormValidation doCheckCountIntervalWorkspace(@QueryParameter String value){ + return checkCrons(value); + } + private void configureJobsCalculation(JSONObject form) { boolean oldCalculationJobs = calculationJobs; String oldcountIntervalJobs = countIntervalJobs; diff --git a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly index d96042bc..69f63648 100644 --- a/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly +++ b/src/main/resources/hudson/plugins/disk_usage/DiskUsageProjectActionFactory/global.jelly @@ -10,21 +10,21 @@ - + - + - + diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages.properties b/src/main/resources/hudson/plugins/disk_usage/Messages.properties index 949a88b9..d1e194a5 100755 --- a/src/main/resources/hudson/plugins/disk_usage/Messages.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages.properties @@ -8,3 +8,4 @@ DiskUsage.Graph.JobDirectory=job DiskUsage.Graph.BuildDirectory=builds DiskUsage.Graph.AgentWorkspaces=agent workspaces DiskUsage.Graph.NonAgentWorkspaces=non-agent workspaces +InvalidCrontab=Invalid cron {0} From 3dae74c8a112df11651e3a1095c92a3841029200 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 1 Apr 2024 23:25:00 +0100 Subject: [PATCH 123/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 886bc9a5..2932c9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Upcoming changes + - [Adds checks for user defined crontab entries](https://github.com/jenkinsci/disk-usage-plugin/pull/96) - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) - [Test with Java 21.](https://github.com/jenkinsci/disk-usage-plugin/pull/94) From 93e5938bf25da074e02d997de169ca38b33b3af4 Mon Sep 17 00:00:00 2001 From: strangelookingnerd <49242855+strangelookingnerd@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:37:09 +0200 Subject: [PATCH 124/158] Enable Jenkins Security Scan --- .github/workflows/jenkins-security-scan.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/jenkins-security-scan.yml diff --git a/.github/workflows/jenkins-security-scan.yml b/.github/workflows/jenkins-security-scan.yml new file mode 100644 index 00000000..c7b41fc2 --- /dev/null +++ b/.github/workflows/jenkins-security-scan.yml @@ -0,0 +1,21 @@ +name: Jenkins Security Scan + +on: + push: + branches: + - master + pull_request: + types: [ opened, synchronize, reopened ] + workflow_dispatch: + +permissions: + security-events: write + contents: read + actions: read + +jobs: + security-scan: + uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 + with: + java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. + # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. From 9bac8a3077046ce9009e5778fd4aba68ba068092 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Wed, 11 Sep 2024 13:03:03 -0600 Subject: [PATCH 125/158] Fix spotbugs warning - invalid method name --- .../plugins/disk_usage/DiskUsageProjectActionFactory.java | 2 +- .../resources/hudson/plugins/disk_usage/Messages.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java index 633ab127..5955c7c8 100644 --- a/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java +++ b/src/main/java/hudson/plugins/disk_usage/DiskUsageProjectActionFactory.java @@ -393,7 +393,7 @@ private FormValidation checkCrons(String cron){ return FormValidation.warning(sanity); } } catch (IllegalArgumentException e){ - return FormValidation.error(Messages.InvalidCrontab(cron)); + return FormValidation.error(Messages.invalidCrontab(cron)); } } public FormValidation doCheckCountIntervalBuilds(@QueryParameter String value){ diff --git a/src/main/resources/hudson/plugins/disk_usage/Messages.properties b/src/main/resources/hudson/plugins/disk_usage/Messages.properties index d1e194a5..5c880d46 100755 --- a/src/main/resources/hudson/plugins/disk_usage/Messages.properties +++ b/src/main/resources/hudson/plugins/disk_usage/Messages.properties @@ -8,4 +8,4 @@ DiskUsage.Graph.JobDirectory=job DiskUsage.Graph.BuildDirectory=builds DiskUsage.Graph.AgentWorkspaces=agent workspaces DiskUsage.Graph.NonAgentWorkspaces=non-agent workspaces -InvalidCrontab=Invalid cron {0} +invalidCrontab=Invalid cron {0} From 0c79cf572ba4d0ec0c65d5eb0019a043ab9d7743 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Sep 2024 10:22:12 +0100 Subject: [PATCH 126/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2932c9b7..48c756de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [Adds checks for user defined crontab entries](https://github.com/jenkinsci/disk-usage-plugin/pull/96) - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) - [Test with Java 21.](https://github.com/jenkinsci/disk-usage-plugin/pull/94) + - [Fix spotbugs warning - invalid method name](https://github.com/jenkinsci/disk-usage-plugin/pull/98) ### Release 1.2 (2023-09-06) From e84a6dda2d8e723c079eeecbe1bbb56741e1f6bc Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 15 Nov 2024 13:29:24 +0000 Subject: [PATCH 127/158] Ads CODEOWNERS file --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..1d3fdd0d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @jenkinsci/disk-usage-plugin-developers + From cf90a9b06ccb1011887908f5588d539b6ec8eed3 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 19 Nov 2024 11:08:41 +0000 Subject: [PATCH 128/158] Upgrade Jenkins core from 2.401.1 to 2.452.4 --- pom.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 342c1d74..2268bb50 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.73 + 4.88 disk-usage @@ -28,15 +28,15 @@ - 2.401.1 + 2.452.4 io.jenkins.tools.bom - bom-2.401.x - 2198.v39c76fc308ca + bom-2.452.x + 3387.v0f2773fa_3200 pom import @@ -63,7 +63,6 @@ org.jenkins-ci.plugins promoted-builds - 892.vd6219fc0a_efb test From 099ff728c63f5eeb23cafc5836d2b2470a474ff1 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 19 Nov 2024 12:41:03 +0000 Subject: [PATCH 129/158] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c756de..4d8ddfa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) - [Test with Java 21.](https://github.com/jenkinsci/disk-usage-plugin/pull/94) - [Fix spotbugs warning - invalid method name](https://github.com/jenkinsci/disk-usage-plugin/pull/98) + - [Upgrade Jenkins core from 2.401.1 to 2.452.4](https://github.com/jenkinsci/disk-usage-plugin/pull/99) ### Release 1.2 (2023-09-06) From bb315f53320e09827c5c56082485c3e9c3f1cf57 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 19 Nov 2024 12:46:23 +0000 Subject: [PATCH 130/158] [maven-release-plugin] prepare release disk-usage-1.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2268bb50..cdf43201 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.3-SNAPSHOT + 1.3 https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - HEAD + disk-usage-1.3 From 41eb7a577bd21b7fd5981ac2a7d84c8f02eeb3d9 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 19 Nov 2024 12:46:27 +0000 Subject: [PATCH 131/158] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cdf43201..63896f4d 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.3 + 1.4-SNAPSHOT https://github.com/jenkinsci/disk-usage-plugin @@ -24,7 +24,7 @@ scm:git:https://github.com/jenkinsci/disk-usage-plugin.git scm:git:git@github.com:jenkinsci/disk-usage-plugin.git https://github.com/jenkinsci/disk-usage-plugin - disk-usage-1.3 + HEAD From b916b2f4329df0e3bbe36b12a2f4d859e459385e Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Tue, 19 Nov 2024 12:52:48 +0000 Subject: [PATCH 132/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8ddfa4..18878595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes +### Release 1.3 (2024-11-19) + - [Adds checks for user defined crontab entries](https://github.com/jenkinsci/disk-usage-plugin/pull/96) - [Modernize to Jenkins 2.387.3](https://github.com/jenkinsci/disk-usage-plugin/pull/93) - [Test with Java 21.](https://github.com/jenkinsci/disk-usage-plugin/pull/94) From 2416ee9db7c706b6f6585efe030170426bce39cb Mon Sep 17 00:00:00 2001 From: strangelookingnerd <49242855+strangelookingnerd@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:41:52 +0100 Subject: [PATCH 133/158] Use `jenkins.baseline` to reduce bom update mistakes --- pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 63896f4d..cde1ba78 100644 --- a/pom.xml +++ b/pom.xml @@ -28,14 +28,16 @@ - 2.452.4 + + 2.452 + ${jenkins.baseline}.4 io.jenkins.tools.bom - bom-2.452.x + bom-${jenkins.baseline}.x 3387.v0f2773fa_3200 pom import From d1b062ab3a16d00e0fe71e41b71dd8d6d1264063 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Wed, 15 Jan 2025 09:39:21 +0000 Subject: [PATCH 134/158] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18878595..949c11eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Upcoming changes + - [Use jenkins.baseline to reduce bom update mistakes](https://github.com/jenkinsci/disk-usage-plugin/pull/100) + ### Release 1.3 (2024-11-19) - [Adds checks for user defined crontab entries](https://github.com/jenkinsci/disk-usage-plugin/pull/96) From c3ad34a058dfa022edf7b06a84eda3fda26de533 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 27 Dec 2025 04:59:34 -0700 Subject: [PATCH 135/158] Require Jenkins 2.479.3 or newer Jenkins 2.479.1 is the first LTS version to require Java 17 or newer. Use 2.479.3 instead of 2.479.1 based on the recommendation in https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ notes that 2.479.1 is the oldest LTS version currently supported by the Jenkins update center. It recommends 2.504.3 and 2.516.3 as good core dependencies. I didn't update to those versions on the assumption that testing with Java 25 was more likely to be accepted if fewer changes were made. --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index cde1ba78..b8d67eb8 100644 --- a/pom.xml +++ b/pom.xml @@ -29,8 +29,8 @@ - 2.452 - ${jenkins.baseline}.4 + 2.479 + ${jenkins.baseline}.3 @@ -38,7 +38,7 @@ io.jenkins.tools.bom bom-${jenkins.baseline}.x - 3387.v0f2773fa_3200 + 5054.v620b_5d2b_d5e6 pom import From 65710b050f8ca5e91793f423a655bbf2f4e9a2ff Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 27 Dec 2025 05:03:27 -0700 Subject: [PATCH 136/158] Use plugin parent pom 5.28 Plugin parent pom 5.28 is new enough to support Java 25 but not so new that it makes the change from JUnit 4 to JUnit Jupiter. Needed to compile and test with Java 25 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b8d67eb8..8cceeda1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.88 + 5.28 disk-usage From 305a5bbde6299fe33b9dd26c291a28f2b8a6fea5 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Sat, 27 Dec 2025 05:04:33 -0700 Subject: [PATCH 137/158] Test with Java 25 and Java 21 Java 25 released September 16, 2025. Jenkins core has supported Java 25 since Jenkins 2.534, Oct 28, 2025. Compile and test on ci.jenkins.io with Java 25 and Java 21. Intentionally continues to generate Java 17 byte code as configured by the plugin parent pom. Does not compile or test with Java 17 any longer because we have found no issues in the past that were specific to the Java 17 compiler. The plan is to drop support for Java 17 in the not too distant future so that the Jenkins project is only supporting two major Java versions at a time, Java 21 and Java 25. Testing done: * Confirmed that automated tests pass with Java 25 --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 54e9032d..fc9129f0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ buildPlugin( timeout: 30, useContainerAgent: true, configurations: [ - [platform: 'linux', jdk: 21], - [platform: 'windows', jdk: 17], + [platform: 'linux', jdk: 25], + [platform: 'windows', jdk: 21], ], ) From c21bb84cfb493f4ab99551d26b0a64b411a04e92 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 28 Dec 2025 14:57:16 +0000 Subject: [PATCH 138/158] Add entry for testing with Java 25 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 949c11eb..2b0889e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Upcoming changes - [Use jenkins.baseline to reduce bom update mistakes](https://github.com/jenkinsci/disk-usage-plugin/pull/100) + - [Test with Java 25](https://github.com/jenkinsci/disk-usage-plugin/pull/101) ### Release 1.3 (2024-11-19) From 11f19781b88dc32b84d5f136c6725679a50e86ac Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 9 Jan 2026 02:19:31 +0000 Subject: [PATCH 139/158] Automate dependency updates --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..03b4d66f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates + +version: 2 +updates: +- package-ecosystem: maven + directory: / + schedule: + interval: monthly +- package-ecosystem: github-actions + directory: / + schedule: + interval: monthly From 6918661d8c85a1fb60bcc985cb359744bd4e65dc Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 9 Jan 2026 03:01:08 +0000 Subject: [PATCH 140/158] Add entry for automating dependency updates --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0889e6..292398c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [Use jenkins.baseline to reduce bom update mistakes](https://github.com/jenkinsci/disk-usage-plugin/pull/100) - [Test with Java 25](https://github.com/jenkinsci/disk-usage-plugin/pull/101) + - [Automate dependency updates](https://github.com/jenkinsci/disk-usage-plugin/pull/103) ### Release 1.3 (2024-11-19) From 55dc190ef70c4fdf2e9899534ed91e215286fd60 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 9 Jan 2026 23:48:01 +0000 Subject: [PATCH 141/158] Use most recent parent pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8cceeda1..ac8eeb5f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 5.28 + 6.2111.v8b_6a_1d599df3 disk-usage From 894cdbc31e0e58ec4cd54e55eab7263fc5167ce1 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 00:17:51 +0000 Subject: [PATCH 142/158] Update CHANGELOG with recent changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 292398c8..4f7b9dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [Use jenkins.baseline to reduce bom update mistakes](https://github.com/jenkinsci/disk-usage-plugin/pull/100) - [Test with Java 25](https://github.com/jenkinsci/disk-usage-plugin/pull/101) - [Automate dependency updates](https://github.com/jenkinsci/disk-usage-plugin/pull/103) + - [Use most recent parent pom 6.2111.v8b_6a_1d599df3](https://github.com/jenkinsci/disk-usage-plugin/pull/104) ### Release 1.3 (2024-11-19) From 521d4eb9571a98270c1107d79509e385765f37a2 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Fri, 9 Jan 2026 01:50:40 +0000 Subject: [PATCH 143/158] Migrate tests to JUnit5 --- pom.xml | 1 + .../disk_usage/DiskUsageCalculationTest.java | 32 ++-- .../plugins/disk_usage/DiskUsageUtilTest.java | 32 ++-- .../integration/BuildDiskUsageActionTest.java | 34 ++-- .../BuildDiskUsageCalculationThreadTest.java | 48 +++-- .../DiskUsageBuildListenerTest.java | 30 ++-- .../integration/DiskUsagePluginTest.java | 48 +++-- .../integration/DiskUsagePropertyTest.java | 168 +++++++++--------- .../integration/DiskUsageUtilTest.java | 94 +++++----- .../JobDiskUsageCalculationThreadTest.java | 40 ++--- .../ProjectDiskUsageActionTest.java | 44 +++-- .../integration/ProjectDiskUsageTest.java | 29 ++- ...rkspaceDiskUsageCalculationThreadTest.java | 74 ++++---- .../DiskUsagePostBuildCalculationTest.java | 22 ++- 14 files changed, 337 insertions(+), 359 deletions(-) diff --git a/pom.xml b/pom.xml index ac8eeb5f..ec94c3bd 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ 2.479 ${jenkins.baseline}.3 + 2545.va_5c4d760c7ef diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 3fdb7369..44f22d72 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -4,7 +4,7 @@ */ package hudson.plugins.disk_usage; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Duration; import java.time.temporal.ChronoUnit; @@ -14,7 +14,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import jenkins.util.Timer; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @@ -28,7 +28,7 @@ public class DiskUsageCalculationTest { * see @testReschedule() */ @Test - public void testScheduledExecutionTime() throws Exception { + void testScheduledExecutionTime() throws Exception { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -39,9 +39,9 @@ public void testScheduledExecutionTime() throws Exception { calculation.getLastTask().cancel(); } long expectedNextExecution = calendar.getTimeInMillis(); - assertEquals("Scheduled time of disk usage calculation should 0, because calculation is not scheduled", 0, calculation.scheduledLastInstanceExecutionTime(), 60000); + assertEquals(0, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should 0, because calculation is not scheduled"); Timer.get().schedule(calculation.getNewInstance(), calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); - assertEquals("Scheduled time of disk usage calculation should be in 10 minutes", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); + assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should be in 10 minutes"); // scheduled time should be changed if configuration of cron is changed calendar.add(Calendar.MINUTE, 10); @@ -49,12 +49,12 @@ public void testScheduledExecutionTime() throws Exception { calculation.setCron(minute + " * * * *"); calculation.reschedule(); expectedNextExecution = calendar.getTimeInMillis(); - assertEquals("Scheduled time of disk usage calculation should be changed", expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000); + assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should be changed"); } @Test - public void testGetRecurrencePeriod() { + void testGetRecurrencePeriod() { GregorianCalendar calendar = new GregorianCalendar(); // for minutes @@ -65,7 +65,7 @@ public void testGetRecurrencePeriod() { TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *"); long period = calculation.getRecurrencePeriod(); long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals("Disk usage calculation should be executed accurately in 2 minutes", expectedPeriod, period, 60000); + assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 minutes"); // for hours calendar = new GregorianCalendar(); @@ -76,7 +76,7 @@ public void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation("0 " + hour + " * * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals("Disk usage calculation should be executed accurately in 2 hours.", expectedPeriod, period, 60000); + assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 hours."); // for days calendar = new GregorianCalendar(); @@ -85,7 +85,7 @@ public void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals("Disk usage calculation should be executed accurately in 2 days.", expectedPeriod, period, 60000); + assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 days."); // for months calendar = new GregorianCalendar(); @@ -95,7 +95,7 @@ public void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals("Disk usage calculation should be executed accurately in 2 months.", expectedPeriod, period, 60000); + assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); // day of week calendar = new GregorianCalendar(); @@ -105,7 +105,7 @@ public void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals("Disk usage calculation should be executed accurately in 2 months.", expectedPeriod, period, 60000); + assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); } @@ -116,7 +116,7 @@ public void testGetRecurrencePeriod() { * see @testScheduledExecutionTime() */ @Test - public void testReschedule() throws Exception { + void testReschedule() throws Exception { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -128,12 +128,12 @@ public void testReschedule() throws Exception { calculation.setCron(minute + " * * * *"); calculation.reschedule(); // should cancel this calculation and schedule new instance - assertEquals("A new calculation should be scheduled with a new scheduled time.", calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000); + assertEquals(calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000, "A new calculation should be scheduled with a new scheduled time."); } @Test - public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { + void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { // attribute currentTask should have value calculation List scheduledInstances = new ArrayList<>(); TestDiskUsageCalculation calculation = (TestDiskUsageCalculation) new TestDiskUsageCalculation("* * * * *").getNewInstance(); @@ -149,7 +149,7 @@ public void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { thread.start(); Thread.sleep(Duration.of(1, ChronoUnit.MINUTES).toMillis()); thread.join(); - assertEquals("Method getRecurencePeriod should not able to schedule more than 1 task in 1 minute", 1, scheduledInstances.size()); + assertEquals(1, scheduledInstances.size(), "Method getRecurencePeriod should not able to schedule more than 1 task in 1 minute"); TestDiskUsageCalculation.stopLoadInstancesHistory(); } diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java index e6030585..9b2aafa0 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageUtilTest.java @@ -1,7 +1,7 @@ package hudson.plugins.disk_usage; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @@ -10,46 +10,46 @@ public class DiskUsageUtilTest { @Test - public void testGetSizeInBytes() { + void testGetSizeInBytes() { String sizeInString = "57 B"; long size = 57L; - Assert.assertEquals("Byte representation of size 57 B is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(size, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size 57 B is wrong."); sizeInString = "5 KB"; size = 1024L * 5; - Assert.assertEquals("Byte representation of size 5 KB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(size, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size 5 KB is wrong."); sizeInString = "9 MB"; size = 1024L * 1024 * 9; - Assert.assertEquals("Byte representation of size 9 MB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(size, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size 9 MB is wrong."); sizeInString = "1 GB"; size = 1024L * 1024 * 1024; - Assert.assertEquals("Byte representation of size 1 GB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(size, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size 1 GB is wrong."); sizeInString = "2 TB"; size = 1024L * 1024 * 1024 * 1024 * 2; - Assert.assertEquals("Byte representation of size 2 TB is wrong.", size, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(size, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size 2 TB is wrong."); sizeInString = "-"; - Assert.assertEquals("Byte representation of size - is wrong.", 0, DiskUsageUtil.getSizeInBytes(sizeInString), 0); + Assertions.assertEquals(0, DiskUsageUtil.getSizeInBytes(sizeInString), 0, "Byte representation of size - is wrong."); } @Test - public void testGetSizeInString() { + void testGetSizeInString() { String sizeInString = "57 B"; long size = 57L; - Assert.assertEquals("String representation of size 57 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 57 B is wrong."); sizeInString = "5 KB"; size = 1024L * 5; - Assert.assertEquals("String representation of size 5 KB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 5 KB is wrong."); sizeInString = "9 MB"; size = 1024L * 1024 * 9; - Assert.assertEquals("String representation of size 9 MB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 9 MB is wrong."); sizeInString = "1 GB"; size = 1024L * 1024 * 1024; - Assert.assertEquals("String representation of size 1 GB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 1 GB is wrong."); sizeInString = "2 TB"; size = 1024L * 1024 * 1024 * 1024 * 2; - Assert.assertEquals("String representation of size 2 TB is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 2 TB is wrong."); sizeInString = "-"; size = 0L; - Assert.assertEquals("String representation of size 0 B is wrong.", sizeInString, DiskUsageUtil.getSizeString(size)); + Assertions.assertEquals(sizeInString, DiskUsageUtil.getSizeString(size), "String representation of size 0 B is wrong."); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java index 2e42d2df..e7dbbdb0 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageActionTest.java @@ -1,6 +1,6 @@ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import hudson.matrix.AxisList; import hudson.matrix.MatrixBuild; @@ -11,21 +11,19 @@ import hudson.model.Action; import hudson.model.FreeStyleProject; import hudson.plugins.disk_usage.BuildDiskUsageAction; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; /** * * @author Lucie Votypkova */ +@WithJenkins public class BuildDiskUsageActionTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test - public void testGetAllDiskUsage() throws Exception { + void testGetAllDiskUsage(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -60,14 +58,14 @@ public void testGetAllDiskUsage() throws Exception { matrixBuild2TotalSize += count * size2; count++; } - assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage()); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).getAllDiskUsage()); - assertEquals("BuildDiskUsageAction for build 2 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild2TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).getAllDiskUsage()); + assertEquals(sizeofBuild, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage(), "BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixBuild1TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild1).getAllDiskUsage(), "BuildDiskUsageAction for build 1 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixBuild2TotalSize, DiskUsageTestUtil.getBuildDiskUsageAction(matrixBuild2).getAllDiskUsage(), "BuildDiskUsageAction for build 2 of MatrixProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); } @Test - public void getBuildUsageStringMatrixProject() throws Exception { + void getBuildUsageStringMatrixProject(JenkinsRule j) throws Exception { MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); TextAxis axis2 = new TextAxis("axis2", "Aaxis", "Baxis", "Caxis"); @@ -100,11 +98,11 @@ public void getBuildUsageStringMatrixProject() throws Exception { } count++; String size = (kiloBytes * count / 1024) + " KB"; - assertEquals("String representation of build disk usage which has " + size + " is wrong.", size, action.getBuildUsageString()); + assertEquals(size, action.getBuildUsageString(), "String representation of build disk usage which has " + size + " is wrong."); } @Test - public void getBuildUsageStringFreeStyleProject() throws Exception { + void getBuildUsageStringFreeStyleProject(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); @@ -114,15 +112,15 @@ public void getBuildUsageStringFreeStyleProject() throws Exception { long gygaBytes = megaBytes * 1024; Long teraBytes = gygaBytes * 1024; DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(bytes); - assertEquals("String representation of build disk usage is wrong which has 100 B is wrong.", "100 B", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); + assertEquals("100 B", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString(), "String representation of build disk usage is wrong which has 100 B is wrong."); DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(kiloBytes); - assertEquals("String representation of build disk usage is wrong which has 2 KB is wrong.", "2 KB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); + assertEquals("2 KB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString(), "String representation of build disk usage is wrong which has 2 KB is wrong."); DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(megaBytes); - assertEquals("String representation of build disk usage is wrong which has 2 MB is wrong.", "2 MB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); + assertEquals("2 MB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString(), "String representation of build disk usage is wrong which has 2 MB is wrong."); DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(gygaBytes); - assertEquals("String representation of build disk usage is wrong which has 2 GB is wrong.", "2 GB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); + assertEquals("2 GB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString(), "String representation of build disk usage is wrong which has 2 GB is wrong."); DiskUsageTestUtil.getBuildDiskUsageAction(build).setDiskUsage(teraBytes); - assertEquals("String representation of build disk usage is wrong which has 2T B is wrong.", "2 TB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString()); + assertEquals("2 TB", DiskUsageTestUtil.getBuildDiskUsageAction(build).getBuildUsageString(), "String representation of build disk usage is wrong which has 2T B is wrong."); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java index 8b82aa1b..5e7f7252 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/BuildDiskUsageCalculationThreadTest.java @@ -1,7 +1,7 @@ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; @@ -28,20 +28,18 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class BuildDiskUsageCalculationThreadTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - private void waitUntilThreadEnds(BuildDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; // wait until thread ends @@ -77,7 +75,7 @@ private Long getSize(List files) { @Test @LocalData - public void testExecute() throws IOException, InterruptedException { + void testExecute(JenkinsRule j) throws IOException, InterruptedException { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -101,18 +99,18 @@ public void testExecute() throws IOException, InterruptedException { waitUntilThreadEnds(calculation); for(AbstractBuild build: buildSizesProject1.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); - assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject1.get(build), size, 0); + assertEquals(buildSizesProject1.get(build), size, 0, "Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size."); } for(AbstractBuild build: buildSizesProject2.keySet()) { Long size = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); - assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), size, 0); + assertEquals(buildSizesProject2.get(build), size, 0, "Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size."); } } @Test @LocalData - public void testExecuteMatrixProject() throws IOException, InterruptedException { + void testExecuteMatrixProject(JenkinsRule j) throws IOException, InterruptedException { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -138,32 +136,32 @@ public void testExecuteMatrixProject() throws IOException, InterruptedException calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); Long size = DiskUsageTestUtil.getBuildDiskUsageAction(project.getBuildByNumber(1)).getDiskUsage(); - assertEquals("Build " + project.getBuildByNumber(1).getNumber() + " of project " + project.getDisplayName() + " has wrong build size.", matrixProjectBuildSize, size, 0); + assertEquals(matrixProjectBuildSize, size, 0, "Build " + project.getBuildByNumber(1).getNumber() + " of project " + project.getDisplayName() + " has wrong build size."); for(AbstractBuild build: buildSizesProject2.keySet()) { Long sizeFreeStyle = DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(); - assertEquals("Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size.", buildSizesProject2.get(build), sizeFreeStyle, 0); + assertEquals(buildSizesProject2.get(build), sizeFreeStyle, 0, "Build " + build.getNumber() + " of project " + build.getProject().getDisplayName() + " has wrong build size."); } for(MatrixConfiguration conf: project.getActiveConfigurations()) { AbstractBuild build = conf.getBuildByNumber(1); - assertEquals("Configuration " + conf.getDisplayName() + " has wrong build size for build 1.", matrixConfigurationBuildsSize.get(conf.getDisplayName()), DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), 0); + assertEquals(matrixConfigurationBuildsSize.get(conf.getDisplayName()), DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), 0, "Configuration " + conf.getDisplayName() + " has wrong build size for build 1."); } } @Test - public void testDoNotCalculateUnenabledDiskUsage() throws Exception { + void testDoNotCalculateUnenabledDiskUsage(JenkinsRule j) throws Exception { FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); FreeStyleBuild build = projectWithoutDiskUsage.createExecutable(); build.save(); DiskUsageProjectActionFactory.DESCRIPTOR.disableBuildsDiskUsageCalculation(); BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for build should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage(), 0); + assertEquals(0l, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage(), 0, "Disk usage for build should not be counted."); DiskUsageProjectActionFactory.DESCRIPTOR.enableBuildsDiskUsageCalculation(); } @Test - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { + void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress(JenkinsRule j) throws Exception { TestFreeStyleProject project = new TestFreeStyleProject(j.jenkins, "project"); FreeStyleBuild build = new FreeStyleBuild(project); project.addBuild(build); @@ -181,7 +179,7 @@ public void run() { t.start(); Thread.sleep(1000); testCalculation.execute(TaskListener.NULL); - assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction(project.getLastBuild()).getAllDiskUsage(), 0); + assertEquals(0l, DiskUsageTestUtil.getBuildDiskUsageAction(project.getLastBuild()).getAllDiskUsage(), 0, "Disk usage should not start calculation if preview calculation is in progress."); t.interrupt(); } @@ -214,7 +212,7 @@ public void save() { } @Test - public void testDoNotCalculateExcludedJobs() throws Exception { + void testDoNotCalculateExcludedJobs(JenkinsRule j) throws Exception { FreeStyleProject excludedJob = j.jenkins.createProject(FreeStyleProject.class, "excludedJob"); FreeStyleProject includedJob = j.jenkins.createProject(FreeStyleProject.class, "includedJob"); List excludes = new ArrayList<>(); @@ -225,24 +223,24 @@ public void testDoNotCalculateExcludedJobs() throws Exception { BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - assertEquals("Disk usage for excluded project should not be counted.", 0l, DiskUsageTestUtil.getBuildDiskUsageAction( - excludedJob.getLastBuild()).getAllDiskUsage(), 0); - assertTrue("Disk usage for excluded project should not be counted.", DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage() > 0); + assertEquals(0l, DiskUsageTestUtil.getBuildDiskUsageAction( + excludedJob.getLastBuild()).getAllDiskUsage(), 0, "Disk usage for excluded project should not be counted."); + assertTrue(DiskUsageTestUtil.getBuildDiskUsageAction(includedJob.getLastBuild()).getAllDiskUsage() > 0, "Disk usage for excluded project should not be counted."); excludes.clear(); } @Test @LocalData - public void testDoNotBreakLazyLoading() throws IOException, InterruptedException { + void testDoNotBreakLazyLoading(JenkinsRule j) throws IOException, InterruptedException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); // method isBuilding() is used for determining disk usage and its calling load some builds project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("Test does not sense if there are all builds loaded, please rewrite it.", loadedBuilds < 8); + assertTrue(loadedBuilds < 8, "Test does not sense if there are all builds loaded, please rewrite it."); BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - assertEquals("Calculation of build disk usage should not cause loading of builds.", loadedBuilds, project._getRuns().getLoadedBuilds().size()); + assertEquals(loadedBuilds, project._getRuns().getLoadedBuilds().size(), "Calculation of build disk usage should not cause loading of builds."); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java index 6085c9f5..a12337d7 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageBuildListenerTest.java @@ -4,43 +4,41 @@ */ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.Functions; import hudson.model.FreeStyleProject; import hudson.plugins.disk_usage.DiskUsageProperty; import hudson.tasks.BatchFile; import hudson.tasks.Shell; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; /** * * @author Lucie Votypkova */ +@WithJenkins public class DiskUsageBuildListenerTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test - public void testOnDeleted() throws Exception { + void testOnDeleted(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); project.getBuildByNumber(2).delete(); - assertNull("Build 2 was not removed from caches informations.", property.getDiskUsageBuildInformation(2)); - assertNotNull("Disk usage property whoud contains cashed information about build 1.", property.getDiskUsageOfBuild(1)); - assertNotNull("Disk usage property whoud contains cashed information about build 3.", property.getDiskUsageOfBuild(3)); + assertNull(property.getDiskUsageBuildInformation(2), "Build 2 was not removed from caches informations."); + assertNotNull(property.getDiskUsageOfBuild(1), "Disk usage property whoud contains cashed information about build 1."); + assertNotNull(property.getDiskUsageOfBuild(3), "Disk usage property whoud contains cashed information about build 3."); } @Test - public void testOnCompleted() throws Exception { + void testOnCompleted(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo ahoj > log.log")); @@ -49,8 +47,8 @@ public void testOnCompleted() throws Exception { } j.buildAndAssertSuccess(project); DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - assertNotNull("Build information is cached.", property.getDiskUsageBuildInformation(1)); - assertTrue("Build disk usage should be counted.", property.getDiskUsageOfBuild(1) > 0); - assertTrue("Workspace of build should be counted.", property.getAllWorkspaceSize() > 0); + assertNotNull(property.getDiskUsageBuildInformation(1), "Build information is cached."); + assertTrue(property.getDiskUsageOfBuild(1) > 0, "Build disk usage should be counted."); + assertTrue(property.getAllWorkspaceSize() > 0, "Workspace of build should be counted."); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java index 0f4b2e53..d2c7ddb9 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePluginTest.java @@ -4,9 +4,9 @@ */ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -16,22 +16,20 @@ import hudson.plugins.disk_usage.DiskUsagePlugin; import hudson.plugins.disk_usage.DiskUsageProperty; import java.io.IOException; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class DiskUsagePluginTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test - public void testRefreshGlobalInformation() throws IOException { + void testRefreshGlobalInformation(JenkinsRule j) throws IOException { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); FreeStyleBuild build1 = project.createExecutable(); FreeStyleBuild build2 = project.createExecutable(); @@ -53,48 +51,48 @@ public void testRefreshGlobalInformation() throws IOException { property.setDiskUsageWithoutBuilds(jobUsage); property.putAgentWorkspaceSize(j.jenkins, j.jenkins.getWorkspaceFor((TopLevelItem) project).getRemote(), workspaceUsage); plugin.refreshGlobalInformation(); - assertEquals("Global build diskUsage should be refreshed.", sizeofBuild1 + sizeofBuild2 + sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0); - assertEquals("Global job diskUsage should be refreshed.", jobUsage, plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), 0); - assertEquals("Global workspace diskUsage should be refreshed.", workspaceUsage, plugin.getCashedGlobalWorkspacesDiskUsage(), 0); + assertEquals(sizeofBuild1 + sizeofBuild2 + sizeofBuild3, plugin.getCashedGlobalBuildsDiskUsage(), 0, "Global build diskUsage should be refreshed."); + assertEquals(jobUsage, plugin.getCashedGlobalJobsWithoutBuildsDiskUsage(), 0, "Global job diskUsage should be refreshed."); + assertEquals(workspaceUsage, plugin.getCashedGlobalWorkspacesDiskUsage(), 0, "Global workspace diskUsage should be refreshed."); } @Test @LocalData - public void testNotBreakLazyLoading() throws IOException { + void testNotBreakLazyLoading(JenkinsRule j) throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); + assertTrue(8 > loadedBuilds, "This tests does not sense if there are loaded all builds."); j.jenkins.getPlugin(DiskUsagePlugin.class).refreshGlobalInformation(); - assertEquals("Size of builds should be loaded.", 47000, j.jenkins.getPlugin(DiskUsagePlugin.class).getCashedGlobalBuildsDiskUsage(), 0); - assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); + assertEquals(47000, j.jenkins.getPlugin(DiskUsagePlugin.class).getCashedGlobalBuildsDiskUsage(), 0, "Size of builds should be loaded."); + assertTrue(loadedBuilds <= project._getRuns().getLoadedBuilds().size(), "No new build should be loaded."); } @Test @LocalData - public void testDoNotLoadAllBuildsDuringStart() { + void testDoNotLoadAllBuildsDuringStart(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); AbstractProject project2 = (AbstractProject) j.jenkins.getItem("project2"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertEquals("Builds of project with disk-usage.xml should not be loaded.", 0, loadedBuilds); + assertEquals(0, loadedBuilds, "Builds of project with disk-usage.xml should not be loaded."); loadedBuilds = project2._getRuns().getLoadedBuilds().size(); - assertEquals("Builds of project without disk-usage.xml should not be loaded.", 0, loadedBuilds); + assertEquals(0, loadedBuilds, "Builds of project without disk-usage.xml should not be loaded."); } @Test @LocalData - public void testDoLoadBuildInformationWhenBuildIsLoaded() { + void testDoLoadBuildInformationWhenBuildIsLoaded(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuild("1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertNotNull("Build should be add after its loading (if it is not present before).", property.getDiskUsageOfBuild(2)); - assertEquals("Only required build should be loaded into Jenkins.", 1, loadedBuilds); + assertNotNull(property.getDiskUsageOfBuild(2), "Build should be add after its loading (if it is not present before)."); + assertEquals(1, loadedBuilds, "Only required build should be loaded into Jenkins."); } @Test @LocalData - public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception { + void testBuildInfoIsNoLoadedMultipleTimes(JenkinsRule j) throws Exception { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuild("2"); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); @@ -103,8 +101,8 @@ public void testBuildInfoIsNoLoadedMultipleTimes() throws Exception { project = (AbstractProject) j.jenkins.getItem("project1"); build = project.getBuild("2"); property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertNotNull("Should be loaded build 2", property.getDiskUsageBuildInformation(2)); - assertEquals("Only one build should be loaded into disk usage build information.", 1, property.getDiskUsageOfBuilds().size()); + assertNotNull(property.getDiskUsageBuildInformation(2), "Should be loaded build 2"); + assertEquals(1, property.getDiskUsageOfBuilds().size(), "Only one build should be loaded into disk usage build information."); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java index 6230cd50..712909af 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsagePropertyTest.java @@ -2,10 +2,10 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import hudson.FilePath; import hudson.Functions; @@ -45,25 +45,23 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRecipe; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class DiskUsagePropertyTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Issue("JENKINS-40728") @Test - public void testCalculationWorkspaceForItemInNonTopLeverGroupItem() throws Exception { + void testCalculationWorkspaceForItemInNonTopLeverGroupItem(JenkinsRule j) throws Exception { final var project = j.createFreeStyleProject("some-project"); JobPropertyImpl property = new JobPropertyImpl(project); project.addProperty(property); @@ -77,7 +75,7 @@ public void testCalculationWorkspaceForItemInNonTopLeverGroupItem() throws Excep } @Test - public void testGetAllDiskUsageWithoutBuilds() throws Exception { + void testGetAllDiskUsageWithoutBuilds(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -102,12 +100,12 @@ public void testGetAllDiskUsageWithoutBuilds() throws Exception { matrixProjectTotalSize += count * size1; count++; } - assertEquals("DiskUsageProperty for FreeStyleProject " + project.getDisplayName() + " returns wrong value its size without builds and including sub-projects.", sizeOfProject, project.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); - assertEquals("DiskUsageProperty for MatrixProject " + project.getDisplayName() + " returns wrong value for its size without builds and including sub-projects.", matrixProjectTotalSize, matrixProject.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds()); + assertEquals(sizeOfProject, project.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), "DiskUsageProperty for FreeStyleProject " + project.getDisplayName() + " returns wrong value its size without builds and including sub-projects."); + assertEquals(matrixProjectTotalSize, matrixProject.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), "DiskUsageProperty for MatrixProject " + project.getDisplayName() + " returns wrong value for its size without builds and including sub-projects."); } @Test - public void testCheckWorkspaces() throws Exception { + void testCheckWorkspaces(JenkinsRule j) throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -126,21 +124,21 @@ public void testCheckWorkspaces() throws Exception { } prop.checkWorkspaces(); Set nodes = prop.getAgentWorkspaceUsage().keySet(); - assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( - agent2.getNodeName())); - assertFalse("DiskUsage property should not contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is not set.", nodes.contains( - agent1.getNodeName())); + assertTrue(nodes.contains( + agent2.getNodeName()), "DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage."); + assertFalse(nodes.contains( + agent1.getNodeName()), "DiskUsage property should not contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is not set."); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(true); prop.checkWorkspaces(); - assertTrue("DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage.", nodes.contains( - agent2.getNodeName())); - assertTrue("DiskUsage property should contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is set.", nodes.contains( - agent1.getNodeName())); + assertTrue(nodes.contains( + agent2.getNodeName()), "DiskUsage property should contains agent " + agent2.getDisplayName() + " in agentWorkspaceUsage."); + assertTrue(nodes.contains( + agent1.getNodeName()), "DiskUsage property should contains agent " + agent1.getDisplayName() + " in agentWorkspaceUsage when detection of user workspace without reference from project is set."); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().setCheckWorkspaceOnAgent(false); } @Test - public void getWorkspaceSizeTest() throws Exception { + void getWorkspaceSizeTest(JenkinsRule j) throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -166,12 +164,12 @@ public void getWorkspaceSizeTest() throws Exception { agentInfo.put(path, workspaceSize); } } - assertEquals("DiskUsage workspaces which is configured as agent workspace is wrong.", workspaceSize * 2, prop.getWorkspaceSize(true), 0); - assertEquals("DiskUsage workspaces which is not configured as agent workspace is wrong.", workspaceSize, prop.getWorkspaceSize(false), 0); + assertEquals(workspaceSize * 2, prop.getWorkspaceSize(true), 0, "DiskUsage workspaces which is configured as agent workspace is wrong."); + assertEquals(workspaceSize, prop.getWorkspaceSize(false), 0, "DiskUsage workspaces which is not configured as agent workspace is wrong."); } @Test - public void testcheckWorkspacesIfAgentIsDeleted() throws Exception { + void testcheckWorkspacesIfAgentIsDeleted(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); @@ -186,14 +184,14 @@ public void testcheckWorkspacesIfAgentIsDeleted() throws Exception { property.putAgentWorkspaceSize(agent2, agent2.getRemoteFS(), 7987l); j.jenkins.removeNode(agent2); property.checkWorkspaces(); - assertFalse("Disk usage property should not contains agent which does not exist.", property.getAgentWorkspaceUsage().containsKey( - agent2.getNodeName())); - assertTrue("Disk usage property should contains agent1.", property.getAgentWorkspaceUsage().containsKey(agent1.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse(property.getAgentWorkspaceUsage().containsKey( + agent2.getNodeName()), "Disk usage property should not contains agent which does not exist."); + assertTrue(property.getAgentWorkspaceUsage().containsKey(agent1.getNodeName()), "Disk usage property should contains agent1."); + assertTrue(property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName()), "Disk usage property should contains jenkins master."); } @Test - public void testCheckWorkspacesIfDoesNotExistsIsDeleted() throws Exception { + void testCheckWorkspacesIfDoesNotExistsIsDeleted(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); DiskUsageProperty property = new DiskUsageProperty(); project.addProperty(property); @@ -207,18 +205,18 @@ public void testCheckWorkspacesIfDoesNotExistsIsDeleted() throws Exception { property.putAgentWorkspaceSize(agent1, agent1.getRemoteFS() + "/project", 5670l); property.putAgentWorkspaceSize(agent2, agent2.getRemoteFS(), 7987l); property.checkWorkspaces(); - assertFalse("Disk usage property should not contains agent which does not have any workspace for its project.", property.getAgentWorkspaceUsage().containsKey( - agent1.getNodeName())); - assertTrue("Disk usage property should contains agent2.", property.getAgentWorkspaceUsage().containsKey(agent2.getNodeName())); - assertTrue("Disk usage property should contains jenkins master.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse(property.getAgentWorkspaceUsage().containsKey( + agent1.getNodeName()), "Disk usage property should not contains agent which does not have any workspace for its project."); + assertTrue(property.getAgentWorkspaceUsage().containsKey(agent2.getNodeName()), "Disk usage property should contains agent2."); + assertTrue(property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName()), "Disk usage property should contains jenkins master."); path.delete(); property.checkWorkspaces(); - assertFalse("Disk usage property should contains jenkins master, because workspace for its project was deleted.", property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName())); + assertFalse(property.getAgentWorkspaceUsage().containsKey(j.jenkins.getNodeName()), "Disk usage property should contains jenkins master, because workspace for its project was deleted."); } @Test - public void testGetAllNonAgentOrCustomWorkspaceSizeWithOnlyAgents() throws Exception { + void testGetAllNonAgentOrCustomWorkspaceSizeWithOnlyAgents(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); @@ -244,14 +242,14 @@ public void testGetAllNonAgentOrCustomWorkspaceSizeWithOnlyAgents() throws Excep project.setCustomWorkspace(customWorkspaceAgent2.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); Long customWorkspaceAgentSize = customWorkspaceAgent1.length() + customWorkspaceAgent2.length() + customWorkspaceAgent1.getParentFile().length() + customWorkspaceAgent2.getParentFile().length(); - assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + assertEquals(customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0, ""); // take one agent offline agent1.toComputer().disconnect(new OfflineCause.ByCLI("test disconnection")); - assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + assertEquals(customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0, ""); } @Test - public void testGetAllNonAgentOrCustomWorkspaceSizeWithMaster() throws Exception { + void testGetAllNonAgentOrCustomWorkspaceSizeWithMaster(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project"); if(Functions.isWindows()) { project.getBuildersList().add(new BatchFile("echo hello > log")); @@ -273,91 +271,91 @@ public void testGetAllNonAgentOrCustomWorkspaceSizeWithMaster() throws Exception project.setCustomWorkspace(customWorkspaceAgent2.getParentFile().getAbsolutePath()); j.buildAndAssertSuccess(project); Long customWorkspaceAgentSize = customWorkspaceAgent1.length() + customWorkspaceAgent2.length() + customWorkspaceAgent1.getParentFile().length() + customWorkspaceAgent2.getParentFile().length(); - assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + assertEquals(customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0, ""); // take one agent offline j.jenkins.setNumExecutors(0); - assertEquals("", customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0); + assertEquals(customWorkspaceAgentSize, project.getProperty(DiskUsageProperty.class).getAllNonAgentOrCustomWorkspaceSize(), 0, ""); } @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml") @LocalData - public void testBackwadrCompatibility2() throws IOException { + void testBackwadrCompatibility2(JenkinsRule j) throws IOException { j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableBuildsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableJobsDiskUsageCalculation(); j.jenkins.getPlugin(DiskUsagePlugin.class).getConfiguration().disableWorkspacesDiskUsageCalculation(); AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); property.getDiskUsage().loadAllBuilds(); - assertEquals("Size of project1 should be loaded from previous configuration.", 188357L, property.getAllDiskUsageWithoutBuilds(), 0); - assertEquals("Size of workspaces should be loaded from previous configuration.", 4096L, property.getAllWorkspaceSize(), 0); - assertTrue("Path of workspace should be loaded form previous configuration.", property.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + assertEquals(188357L, property.getAllDiskUsageWithoutBuilds(), 0, "Size of project1 should be loaded from previous configuration."); + assertEquals(4096L, property.getAllWorkspaceSize(), 0, "Size of workspaces should be loaded from previous configuration."); + assertTrue(property.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace"), "Path of workspace should be loaded form previous configuration."); } @Test @LocalData - public void testGetDiskUsageOfBuilds() { + void testGetDiskUsageOfBuilds(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); for(DiskUsageBuildInformation information: property.getDiskUsageOfBuilds()) { - assertEquals("Disk usage of build has loaded wrong size.", information.getNumber() * 1000, information.getSize(), 0); + assertEquals(information.getNumber() * 1000, information.getSize(), 0, "Disk usage of build has loaded wrong size."); } - assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); + assertEquals(loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0, "No build should be loaded."); } @Test @LocalData - public void testGetDiskUsageOfBuild() { + void testGetDiskUsageOfBuild(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild("1"), 0); - assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild("7"), 0); - assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); + assertEquals(3000, property.getDiskUsageOfBuild("1"), 0, "Build with id 1 should have size 3000"); + assertEquals(10000, property.getDiskUsageOfBuild("7"), 0, "Build with id 7 should have size 10000"); + assertEquals(loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0, "No build should be loaded."); } @Test @LocalData - public void testGetDiskUsageBuildInformation() { + void testGetDiskUsageBuildInformation(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageBuildInformation("1").getSize(), 0); - assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageBuildInformation("7").getSize(), 0); - assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); + assertEquals(3000, property.getDiskUsageBuildInformation("1").getSize(), 0, "Build with id 1 should have size 3000"); + assertEquals(10000, property.getDiskUsageBuildInformation("7").getSize(), 0, "Build with id 7 should have size 10000"); + assertEquals(loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0, "No build should be loaded."); } @Test @LocalData - public void testGetDiskUsageOfBuildByNumber() { + void testGetDiskUsageOfBuildByNumber(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Build with id 1 should have size 3000", 3000, property.getDiskUsageOfBuild(1), 0); - assertEquals("Build with id 7 should have size 10000", 10000, property.getDiskUsageOfBuild(7), 0); - assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); + assertEquals(3000, property.getDiskUsageOfBuild(1), 0, "Build with id 1 should have size 3000"); + assertEquals(10000, property.getDiskUsageOfBuild(7), 0, "Build with id 7 should have size 10000"); + assertEquals(loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0, "No build should be loaded."); } @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/disk-usage.xml") @LocalData - public void testCheckWorkspacesBuildsWithoutLoadingBuilds() throws IOException, InterruptedException { + void testCheckWorkspacesBuildsWithoutLoadingBuilds(JenkinsRule j) throws IOException, InterruptedException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuildsSize = project._getRuns().getLoadedBuilds().size(); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); FilePath f = j.jenkins.getWorkspaceFor((TopLevelItem) project); property.checkWorkspaces(); - assertEquals("Workspace should have size 4096", 4096, property.getAllWorkspaceSize(), 0); - assertEquals("No build should be loaded.", loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0); + assertEquals(4096, property.getAllWorkspaceSize(), 0, "Workspace should have size 4096"); + assertEquals(loadedBuildsSize, project._getRuns().getLoadedBuilds().size(), 0, "No build should be loaded."); } @Test @ReplaceHudsonHomeWithCurrentPath("jobs/project1/config.xml, jobs/project1/builds/1/build.xml, jobs/project1/builds/3/build.xml") @LocalData - public void testCheckWorkspacesWithLoadingBuilds() throws IOException { + void testCheckWorkspacesWithLoadingBuilds(JenkinsRule j) throws IOException { File file = new File(j.jenkins.getRootDir(), "jobs/project2/builds/1/build.xml"); XmlFile f = new XmlFile(new XStream2(), file); String newBuildXml = f.asString().replace("${JENKINS_HOME}", j.jenkins.getRootDir().getAbsolutePath()); @@ -368,14 +366,14 @@ public void testCheckWorkspacesWithLoadingBuilds() throws IOException { DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); DiskUsageProperty property2 = (DiskUsageProperty) project2.getProperty(DiskUsageProperty.class); property2.getDiskUsage().loadAllBuilds(); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace", property.getAgentWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace")); - assertTrue("Project should contains workspace with path {JENKINS_HOME}/workspace", property2.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace")); + assertTrue(property.getAgentWorkspaceUsage().get("").containsKey("${JENKINS_HOME}/jobs/project1/workspace"), "Project should contains workspace with path {JENKINS_HOME}/jobs/project1/workspace"); + assertTrue(property2.getAgentWorkspaceUsage().get("").containsKey(j.jenkins.getRootDir().getAbsolutePath() + "/workspace"), "Project should contains workspace with path {JENKINS_HOME}/workspace"); - assertEquals("Builds should be loaded.", 2, project2._getRuns().getLoadedBuilds().size(), 0); + assertEquals(2, project2._getRuns().getLoadedBuilds().size(), 0, "Builds should be loaded."); } @Test - public void testGetAllDiskUsageOfBuild() throws IOException, Exception { + void testGetAllDiskUsageOfBuild(JenkinsRule j) throws IOException, Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -412,38 +410,38 @@ public void testGetAllDiskUsageOfBuild() throws IOException, Exception { } hudson.plugins.disk_usage.DiskUsageProperty freeStyleProjectProperty = project.getProperty(DiskUsageProperty.class); DiskUsageProperty matrixProjectProperty = matrixProject.getProperty(DiskUsageProperty.class); - assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, freeStyleProjectProperty.getAllDiskUsageOfBuild(1)); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(1)); - assertEquals("BuildDiskUsageAction for build 2 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild2TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(2)); + assertEquals(sizeofBuild, freeStyleProjectProperty.getAllDiskUsageOfBuild(1), "BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixBuild1TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(1), "BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixBuild2TotalSize, matrixProjectProperty.getAllDiskUsageOfBuild(2), "BuildDiskUsageAction for build 2 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds."); } @Test @LocalData - public void testDoNotBreakLazyLoading() { + void testDoNotBreakLazyLoading(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This tests does not sense if there are loaded all builds.", 8 > loadedBuilds); + assertTrue(8 > loadedBuilds, "This tests does not sense if there are loaded all builds."); DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class); - assertEquals("Size of builds should be loaded.", 1000, property.getAllDiskUsageOfBuild(8), 0); - assertEquals("Size of builds should be loaded.", 7000, property.getAllDiskUsageOfBuild(4), 0); - assertTrue("No new build should be loaded.", loadedBuilds <= project._getRuns().getLoadedBuilds().size()); + assertEquals(1000, property.getAllDiskUsageOfBuild(8), 0, "Size of builds should be loaded."); + assertEquals(7000, property.getAllDiskUsageOfBuild(4), 0, "Size of builds should be loaded."); + assertTrue(loadedBuilds <= project._getRuns().getLoadedBuilds().size(), "No new build should be loaded."); } @Test - public void testRemoveBuild() throws Exception { + void testRemoveBuild(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - assertEquals("Disk usage should have information about two builds.", 2, property.getDiskUsage().getBuildDiskUsage(false).size()); + assertEquals(2, property.getDiskUsage().getBuildDiskUsage(false).size(), "Disk usage should have information about two builds."); AbstractBuild build = project.getLastBuild(); build.delete(); - assertEquals("Deleted build should be removed from disk-usage informations too.", 1, property.getDiskUsage().getBuildDiskUsage(false).size()); + assertEquals(1, property.getDiskUsage().getBuildDiskUsage(false).size(), "Deleted build should be removed from disk-usage informations too."); } @Test - public void testRemoveDeletedBuildNotLoadedByJenkins() throws Exception { + void testRemoveDeletedBuildNotLoadedByJenkins(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project); @@ -452,12 +450,12 @@ public void testRemoveDeletedBuildNotLoadedByJenkins() throws Exception { FilePath path = new FilePath(file); path.deleteRecursive(); DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - assertFalse("It is not possible to delete build.", file.exists()); - assertEquals("Disk usage should have information about 2 builds.", 2, property.getDiskUsage().getBuildDiskUsage(false).size()); + assertFalse(file.exists(), "It is not possible to delete build."); + assertEquals(2, property.getDiskUsage().getBuildDiskUsage(false).size(), "Disk usage should have information about 2 builds."); j.jenkins.reload(); project = (FreeStyleProject) j.jenkins.getItem(project.getDisplayName()); property = project.getProperty(DiskUsageProperty.class); - assertEquals("Deleted build without Jenkins should not be loaded.", 1, property.getDiskUsage().getBuildDiskUsage(false).size()); + assertEquals(1, property.getDiskUsage().getBuildDiskUsage(false).size(), "Deleted build without Jenkins should not be loaded."); } @@ -542,7 +540,7 @@ private void checkForConcurrencyException(Exception exception) { @Issue("JENKINS-29143") @Test - public void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation() throws Exception { + void testThreadSaveOperationUnderSetOfDiskUsageBuildInformation(JenkinsRule j) throws Exception { final FreeStyleProject project = j.createFreeStyleProject(); final ProjectDiskUsage diskUsage = new ProjectDiskUsage(); diskUsage.setProject(project); diff --git a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java index 1ec00ae7..1234a079 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/DiskUsageUtilTest.java @@ -1,7 +1,7 @@ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.matrix.AxisList; import hudson.matrix.LabelAxis; @@ -22,35 +22,33 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class DiskUsageUtilTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test @LocalData - public void testCalculateDiskUsageForBuild() throws Exception { + void testCalculateDiskUsageForBuild(JenkinsRule j) throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuildByNumber(2); File file = new File(build.getRootDir(), "fileList"); Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + build.getRootDir().length(); DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), project); - Assert.assertEquals("Calculation of build disk usage does not return right size of build directory.", size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage()); + Assertions.assertEquals(size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), "Calculation of build disk usage does not return right size of build directory."); } @Test @LocalData - public void testCalculateDiskUsageForMatrixBuild() throws Exception { + void testCalculateDiskUsageForMatrixBuild(JenkinsRule j) throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); AbstractBuild build = project.getBuildByNumber(1); File file = new File(build.getRootDir(), "fileList"); @@ -62,16 +60,16 @@ public void testCalculateDiskUsageForMatrixBuild() throws Exception { sizeAll += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(f)) + b.getRootDir().length(); } DiskUsageUtil.calculateDiskUsageForBuild(build.getId(), project); - Assert.assertEquals("Matrix project project1 has disk usage size.", size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage()); + Assertions.assertEquals(size, DiskUsageTestUtil.getBuildDiskUsageAction(build).getDiskUsage(), "Matrix project project1 has disk usage size."); for(MatrixConfiguration config: project.getActiveConfigurations()) { DiskUsageUtil.calculateDiskUsageForBuild(config.getBuildByNumber(1).getId(), config); } - Assert.assertEquals("Matrix project project1 has wrong size for its build.", sizeAll, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage()); + Assertions.assertEquals(sizeAll, DiskUsageTestUtil.getBuildDiskUsageAction(build).getAllDiskUsage(), "Matrix project project1 has wrong size for its build."); } @Test @LocalData - public void testCalculateDiskUsageForJob() throws Exception { + void testCalculateDiskUsageForJob(JenkinsRule j) throws Exception { FreeStyleProject project = (FreeStyleProject) j.jenkins.getItem("project1"); // all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -79,13 +77,13 @@ public void testCalculateDiskUsageForJob() throws Exception { Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + project.getRootDir().length(); size += project.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); DiskUsageUtil.calculateDiskUsageForProject(project); - Assert.assertEquals("Calculation of job disk usage does not return right size of job without builds.", size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds()); + Assertions.assertEquals(size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), "Calculation of job disk usage does not return right size of job without builds."); } @Test @LocalData - public void testCalculateDiskUsageForMatrixJob() throws Exception { + void testCalculateDiskUsageForMatrixJob(JenkinsRule j) throws Exception { MatrixProject project = (MatrixProject) j.jenkins.getItem("project1"); // all builds has to be loaded project.getProperty(DiskUsageProperty.class).getDiskUsage().loadAllBuilds(); @@ -100,17 +98,17 @@ public void testCalculateDiskUsageForMatrixJob() throws Exception { sizeAll += config.getProperty(DiskUsageProperty.class).getProjectDiskUsage().getConfigFile().getFile().length(); } DiskUsageUtil.calculateDiskUsageForProject(project); - Assert.assertEquals("Calculation of job disk usage does not return right size of job without builds.", size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds()); + Assertions.assertEquals(size, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), "Calculation of job disk usage does not return right size of job without builds."); for(AbstractProject p: project.getItems()) { DiskUsageUtil.calculateDiskUsageForProject(p); } - Assert.assertEquals("Calculation of job disk usage does not return right size of job and its sub-jobs without builds.", sizeAll, project.getAction(ProjectDiskUsageAction.class).getAllDiskUsageWithoutBuilds()); + Assertions.assertEquals(sizeAll, project.getAction(ProjectDiskUsageAction.class).getAllDiskUsageWithoutBuilds(), "Calculation of job disk usage does not return right size of job and its sub-jobs without builds."); } @Test @LocalData - public void testCalculateDiskUsageWorkspaceForProject() throws Exception { + void testCalculateDiskUsageWorkspaceForProject(JenkinsRule j) throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -131,16 +129,16 @@ public void testCalculateDiskUsageWorkspaceForProject() throws Exception { Long size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project1).length(); size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file2)) + agent2.getWorkspaceFor(project1).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of job workspace disk usage does not return right size."); file = new File(agent1.getWorkspaceFor(project2).getRemote(), "fileList"); size = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent1.getWorkspaceFor(project2).length() + agent2.getWorkspaceFor(project2).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project2); - Assert.assertEquals("Calculation of job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of job workspace disk usage does not return right size."); } @Test @LocalData - public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory() throws Exception { + void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSameDirectory(JenkinsRule j) throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -174,11 +172,11 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa DiskUsageUtil.calculateWorkspaceDiskUsage(c); } DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix job workspace disk usage does not return right size."); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); // next build - configuration are built on next agent @@ -190,9 +188,9 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa } DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); fileAxis1 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis1/label/agent2", "fileList"); fileAxis2 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2", "fileList"); fileAxis3 = new File(agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2", "fileList"); @@ -202,9 +200,9 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2/label/agent2").length(); sizeAxis3 = DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(fileAxis3)) + new File( agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3/label/agent2").length(); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - Assert.assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(sizeAxis1, project1.getItem("axis=axis1,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis2, project1.getItem("axis=axis2,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + Assertions.assertEquals(sizeAxis3, project1.getItem("axis=axis3,label=agent2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); // matrix project is built on the next agent @@ -214,12 +212,12 @@ public void testCalculateDiskUsageWorkspaceForMatrixProjectWithConfigurationInSa file = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent2.getWorkspaceFor(project1).length(); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix job workspace disk usage does not return right size."); } @Test @LocalData - public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() throws Exception { + void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists(JenkinsRule j) throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -249,13 +247,13 @@ public void testCalculateDiskUsageWorkspaceWhenReferenceFromJobDoesNotExists() t file = new File(agent2.getWorkspaceFor(project1).getRemote(), "fileList"); size += DiskUsageTestUtil.getSize(DiskUsageTestUtil.readFileList(file)) + agent2.getWorkspaceFor(project1).length() + sizeAxis1 + sizeAxis2 + sizeAxis3; DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - Assert.assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + Assertions.assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix job workspace disk usage does not return right size."); plugin.getConfiguration().setCheckWorkspaceOnAgent(false); } @Test - public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists() throws Exception { + void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesNotExists(JenkinsRule j) throws Exception { RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.jenkins.getRootDir(), "workspace1").getPath(), j.jenkins, j.createComputerLauncher(null)); @@ -271,32 +269,32 @@ public void testCalculateDiskUsageWorkspaceUpdateIformationIfSavedWorkspaceDoesN } prop.putAgentWorkspaceSize(agent2, agent2.getWorkspaceFor((TopLevelItem) project1).getRemote(), 54356l); DiskUsageUtil.calculateWorkspaceDiskUsage(project1); - assertFalse("Agent agent2 should be removed from disk usage, because a workspace for project1 does not exist on this agent.", prop.getAgentWorkspaceUsage().containsKey( - agent2.getNodeName())); - assertTrue("Disk usage should contains agent1, there is a workspace for project1.", prop.getAgentWorkspaceUsage().containsKey( - agent1.getNodeName())); + assertFalse(prop.getAgentWorkspaceUsage().containsKey( + agent2.getNodeName()), "Agent agent2 should be removed from disk usage, because a workspace for project1 does not exist on this agent."); + assertTrue(prop.getAgentWorkspaceUsage().containsKey( + agent1.getNodeName()), "Disk usage should contains agent1, there is a workspace for project1."); } @Test - public void testParseExcludedJobsFromString() throws Exception { + void testParseExcludedJobsFromString(JenkinsRule j) throws Exception { FreeStyleProject projectWithSpace = j.createFreeStyleProject("Project with space"); FreeStyleProject project = j.createFreeStyleProject("Project"); FreeStyleProject project2 = j.createFreeStyleProject("Project2"); FreeStyleProject projectWithSpace2 = j.createFreeStyleProject(" Project with space"); String excluded = "Project with space,Project"; List excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); - assertTrue("Excluded jobs should contains job without spaces in name", excludedJobs.contains(project.getName())); - assertTrue("Excluded jobs should contains job with spaces in name", excludedJobs.contains(projectWithSpace.getName())); + assertTrue(excludedJobs.contains(project.getName()), "Excluded jobs should contains job without spaces in name"); + assertTrue(excludedJobs.contains(projectWithSpace.getName()), "Excluded jobs should contains job with spaces in name"); excluded = "Project with space, Project"; excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); - assertTrue("Excluded jobs should parse jobs with spaces even if the space is used as separator.", excludedJobs.contains(projectWithSpace.getName())); - assertFalse("Excluded jobs should parse jobs correctly even if the space is used as separator.", excludedJobs.contains(projectWithSpace2.getName())); - assertFalse("Excluded jobs should not contains jobs which is not occuren in excluded string.", excludedJobs.contains(project2.getName())); + assertTrue(excludedJobs.contains(projectWithSpace.getName()), "Excluded jobs should parse jobs with spaces even if the space is used as separator."); + assertFalse(excludedJobs.contains(projectWithSpace2.getName()), "Excluded jobs should parse jobs correctly even if the space is used as separator."); + assertFalse(excludedJobs.contains(project2.getName()), "Excluded jobs should not contains jobs which is not occuren in excluded string."); excluded = "Project with space, Project5"; excludedJobs = DiskUsageUtil.parseExcludedJobsFromString(excluded); - assertFalse("Excluded jobs should not contains jobs which does not exists.", excludedJobs.contains("Project5")); + assertFalse(excludedJobs.contains("Project5"), "Excluded jobs should not contains jobs which does not exists."); excluded = "Project with space, "; - assertTrue("Excluded jobs should be parsed correctly even if there additional separator", excludedJobs.contains(projectWithSpace.getName()) && excludedJobs.size() == 1); + assertTrue(excludedJobs.contains(projectWithSpace.getName()) && excludedJobs.size() == 1, "Excluded jobs should be parsed correctly even if there additional separator"); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java index 48ac5efc..fd22677f 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/JobDiskUsageCalculationThreadTest.java @@ -1,7 +1,7 @@ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; @@ -26,20 +26,18 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class JobDiskUsageCalculationThreadTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - private void waitUntilThreadEnds(JobWithoutBuildsDiskUsageCalculation calculation) throws InterruptedException { while(calculation.isExecuting()) { Thread.sleep(100); @@ -68,7 +66,7 @@ private Long getSize(List files) { @Test @LocalData - public void testExecute() throws IOException, InterruptedException { + void testExecute(JenkinsRule j) throws IOException, InterruptedException { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.jenkins.getExtensionList(RunListener.class).remove(listener); @@ -90,13 +88,13 @@ public void testExecute() throws IOException, InterruptedException { } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - assertEquals("Project project has wrong job size.", projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); - assertEquals("Project project2 has wrong job size.", project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); + assertEquals(projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Project project has wrong job size."); + assertEquals(project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Project project2 has wrong job size."); } @Test @LocalData - public void testMatrixProject() throws IOException, InterruptedException { + void testMatrixProject(JenkinsRule j) throws IOException, InterruptedException { // turn off run listener DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); @@ -126,15 +124,15 @@ public void testMatrixProject() throws IOException, InterruptedException { } calculation.execute(TaskListener.NULL); waitUntilThreadEnds(calculation); - assertEquals("Project project has wrong job size.", projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); - assertEquals("Project project2 has wrong job size.", project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); + assertEquals(projectSize, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Project project has wrong job size."); + assertEquals(project2Size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Project project2 has wrong job size."); for(MatrixConfiguration config: project.getItems()) { - assertEquals("Configuration " + config.getDisplayName() + " has wrong job size.", matrixConfigurationsSize.get(config.getDisplayName()), config.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); + assertEquals(matrixConfigurationsSize.get(config.getDisplayName()), config.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Configuration " + config.getDisplayName() + " has wrong job size."); } } @Test - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { + void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress(JenkinsRule j) throws Exception { JobWithoutBuildsDiskUsageCalculation calculation = new JobWithoutBuildsDiskUsageCalculation(); DiskUsageTestUtil.cancelCalculation(calculation); FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "freestyle1"); @@ -152,22 +150,22 @@ public void run() { t.start(); Thread.sleep(1000); testCalculation.doRun(); - assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0l, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0); + assertEquals(0l, project.getAction(ProjectDiskUsageAction.class).getDiskUsageWithoutBuilds(), 0, "Disk usage should not start calculation if preview calculation is in progress."); t.interrupt(); } @Test - public void testDoNotCalculateUnenabledDiskUsage() throws Exception { + void testDoNotCalculateUnenabledDiskUsage(JenkinsRule j) throws Exception { FreeStyleProject projectWithoutDiskUsage = j.jenkins.createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); DiskUsageProjectActionFactory.DESCRIPTOR.disableJobsDiskUsageCalculation(); JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for build should not be counted.", 0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0); + assertEquals(0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0, "Disk usage for build should not be counted."); DiskUsageProjectActionFactory.DESCRIPTOR.enableJobsDiskUsageCalculation(); } @Test - public void testDoNotCalculateExcludedJobs() throws Exception { + void testDoNotCalculateExcludedJobs(JenkinsRule j) throws Exception { JobWithoutBuildsDiskUsageCalculation calculation = AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); if(calculation.isExecuting()) { DiskUsageTestUtil.cancelCalculation(calculation); @@ -178,8 +176,8 @@ public void testDoNotCalculateExcludedJobs() throws Exception { excludes.add(excludedJob.getName()); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for excluded project should not be counted.", 0, excludedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0); - assertTrue("Disk usage for included project should be not be counted.", includedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds() > 0); + assertEquals(0, excludedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds(), 0, "Disk usage for excluded project should not be counted."); + assertTrue(includedJob.getProperty(DiskUsageProperty.class).getAllDiskUsageWithoutBuilds() > 0, "Disk usage for included project should be not be counted."); excludes.clear(); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java index 56c9f818..ccac7776 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageActionTest.java @@ -1,7 +1,7 @@ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.matrix.AxisList; import hudson.matrix.MatrixBuild; @@ -23,22 +23,20 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.Map; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class ProjectDiskUsageActionTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test - public void testGetBuildsDiskUsage() throws Exception { + void testGetBuildsDiskUsage(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -74,13 +72,13 @@ public void testGetBuildsDiskUsage() throws Exception { count++; } Long matrixProjectBuildsTotalSize = matrixBuild1TotalSize + matrixBuild2TotalSize; - assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); + assertEquals(sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all"), "BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixProjectBuildsTotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all"), "BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds."); } @Test - public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { + void testGetBuildsDiskUsageNotDeletedConfigurations(JenkinsRule j) throws Exception { FreeStyleProject project = j.jenkins.createProject(FreeStyleProject.class, "project1"); MatrixProject matrixProject = j.jenkins.createProject(MatrixProject.class, "project2"); TextAxis axis1 = new TextAxis("axis", "axisA", "axisB", "axisC"); @@ -120,13 +118,13 @@ public void testGetBuildsDiskUsageNotDeletedConfigurations() throws Exception { matrixBuild2.delete(); - assertEquals("BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds.", sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all")); - assertEquals("BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds.", matrixBuild1TotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all").longValue()); + assertEquals(sizeofBuild, project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all"), "BuildDiskUsageAction for build 1 of FreeStyleProject " + project.getDisplayName() + " returns wrong value for its size including sub-builds."); + assertEquals(matrixBuild1TotalSize, matrixProject.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage().get("all").longValue(), "BuildDiskUsageAction for build 1 of MatrixProject " + matrixProject.getDisplayName() + " returns wrong value for its size including sub-builds."); } @Test - public void getAllBuildDiskUsageFiltered() throws Exception { + void getAllBuildDiskUsageFiltered(JenkinsRule j) throws Exception { ProjectTest project = new ProjectTest(j.jenkins, "project"); Calendar calendar1 = new GregorianCalendar(); Calendar calendar2 = new GregorianCalendar(); @@ -156,30 +154,30 @@ public void getAllBuildDiskUsageFiltered() throws Exception { DiskUsageTestUtil.getBuildDiskUsageAction(build3).setDiskUsage(sizeofBuild3); project.update(); Map size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(null, youngerThan10days); - assertEquals("Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago).", sizeofBuild1, size.get("all"), 0); + assertEquals(sizeofBuild1, size.get("all"), 0, "Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago)."); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan7days, youngerThan10days); - assertEquals("Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago and older than 8 days ago).", 0, size.get("all"), 0); + assertEquals(0, size.get("all"), 0, "Disk usage of builds should count only build 1 (only build 1 is younger than 10 days ago and older than 8 days ago)."); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan7days, null); - assertEquals("Disk usage of builds should count all builds (all builds is older than 7 days ago).", sizeofBuild2 + sizeofBuild3, size.get("all"), 0); + assertEquals(sizeofBuild2 + sizeofBuild3, size.get("all"), 0, "Disk usage of builds should count all builds (all builds is older than 7 days ago)."); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan7days, youngerThan3weeks); - assertEquals("Disk usage of builds should count build 1 and build 2 (build 1 and build 2 are older than 7 days but younger that 3 weeks).", sizeofBuild2, size.get("all"), 0); + assertEquals(sizeofBuild2, size.get("all"), 0, "Disk usage of builds should count build 1 and build 2 (build 1 and build 2 are older than 7 days but younger that 3 weeks)."); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan5months, null); - assertEquals("No builds is older than 5 months ago", 0, size.get("all"), 0); + assertEquals(0, size.get("all"), 0, "No builds is older than 5 months ago"); size = project.getAction(ProjectDiskUsageAction.class).getBuildsDiskUsage(olderThan3weeks, null); - assertEquals("Disk usage of builds should count only build 3 (only build 3 is older tah 3 weeks).", sizeofBuild3, size.get("all"), 0); + assertEquals(sizeofBuild3, size.get("all"), 0, "Disk usage of builds should count only build 3 (only build 3 is older tah 3 weeks)."); } @Test @LocalData - public void testNotToBreakLazyLoading() throws IOException { + void testNotToBreakLazyLoading(JenkinsRule j) throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); + assertTrue(8 > loadedBuilds, "This test does not have sense if there is loaded all builds"); project.getAction(ProjectDiskUsageAction.class).getGraph(); - assertTrue("Creation of graph should not cause loading of builds.", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); + assertTrue(project._getRuns().getLoadedBuilds().size() <= loadedBuilds, "Creation of graph should not cause loading of builds."); } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java index 410db141..51510eae 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/ProjectDiskUsageTest.java @@ -4,8 +4,8 @@ */ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.model.AbstractProject; import hudson.plugins.disk_usage.DiskUsageBuildInformation; @@ -13,47 +13,44 @@ import hudson.plugins.disk_usage.ProjectDiskUsageAction; import java.io.IOException; import java.util.Set; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author lucinka */ +@WithJenkins public class ProjectDiskUsageTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Test @LocalData - public void testAllInfoLoaded() throws IOException { + void testAllInfoLoaded(JenkinsRule j) throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); Set informations = project.getAction(ProjectDiskUsageAction.class).getBuildsInformation(); - assertEquals("Number of loaded builds should be the same.", loadedBuilds, project._getRuns().getLoadedBuilds().size()); - assertEquals("Set of DisUsageBuildInformation does not contains all builds of job.", 8, informations.size()); - assertTrue("The test have to be rewritten because loaded builds is not less then all builds.", 8 > loadedBuilds); + assertEquals(loadedBuilds, project._getRuns().getLoadedBuilds().size(), "Number of loaded builds should be the same."); + assertEquals(8, informations.size(), "Set of DisUsageBuildInformation does not contains all builds of job."); + assertTrue(8 > loadedBuilds, "The test have to be rewritten because loaded builds is not less then all builds."); } @Test @LocalData - public void testFirstLoad() throws IOException { + void testFirstLoad(JenkinsRule j) throws IOException { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); Set informations = project.getProperty(DiskUsageProperty.class) .getDiskUsage().getBuildDiskUsage(false); - assertEquals("Set of DisUsageBuildInformation should not contain information about builds because they are not loaded.", 0, informations.size()); + assertEquals(0, informations.size(), "Set of DisUsageBuildInformation should not contain information about builds because they are not loaded."); } @Test @LocalData - public void testLoadingAllBuildInformationFromPreviousVersion() { + void testLoadingAllBuildInformationFromPreviousVersion(JenkinsRule j) { AbstractProject project = (AbstractProject) j.jenkins.getItem("project1"); DiskUsageProperty property = project.getProperty(DiskUsageProperty.class); - assertEquals("Builds information should be loaded.", 8, property.getDiskUsage().getBuildDiskUsage(true).size(), 0); + assertEquals(8, property.getDiskUsage().getBuildDiskUsage(true).size(), 0, "Builds information should be loaded."); } } diff --git a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java index f188f182..e65f2f9e 100644 --- a/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java +++ b/src/test/java/hudson/plugins/disk_usage/integration/WorkspaceDiskUsageCalculationThreadTest.java @@ -4,9 +4,9 @@ */ package hudson.plugins.disk_usage.integration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Functions; @@ -46,21 +46,19 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; /** * * @author Lucie Votypkova */ +@WithJenkins public class WorkspaceDiskUsageCalculationThreadTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - private void waitUntilThreadEnds(WorkspaceDiskUsageCalculationThread calculation) throws InterruptedException { Thread thread = null; // wait until thread ends @@ -95,7 +93,7 @@ private Long getSize(List files) { return length; } - private Slave createAgent(String name, String remoteFS) throws Exception { + private Slave createAgent(JenkinsRule j, String name, String remoteFS) throws Exception { DumbSlave agent = new DumbSlave(name, "dummy", remoteFS, "2", Mode.NORMAL, "", j.createComputerLauncher(null), RetentionStrategy.NOOP, Collections.>emptyList()); @@ -108,12 +106,12 @@ private Slave createAgent(String name, String remoteFS) throws Exception { @Test @LocalData - public void testExecute() throws IOException, InterruptedException, Exception { + void testExecute(JenkinsRule j) throws IOException, InterruptedException, Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); - Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); - Slave agent2 = createAgent("agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); + Slave agent1 = createAgent(j, "agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave agent2 = createAgent(j, "agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); FreeStyleProject project1 = j.createFreeStyleProject("project1"); FreeStyleProject project2 = j.createFreeStyleProject("project2"); project1.setAssignedNode(agent1); @@ -135,18 +133,18 @@ public void testExecute() throws IOException, InterruptedException, Exception { } thread.execute(TaskListener.NULL); waitUntilThreadEnds(thread); - assertEquals("Calculation of job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - assertEquals("Calculation of job workspace disk usage does not return right size.", size2, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of job workspace disk usage does not return right size."); + assertEquals(size2, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of job workspace disk usage does not return right size."); } @Test @LocalData - public void testExecuteMatrixProject() throws Exception { + void testExecuteMatrixProject(JenkinsRule j) throws Exception { // turn off run listener RunListener listener = RunListener.all().get(DiskUsageBuildListener.class); j.getInstance().getExtensionList(RunListener.class).remove(listener); j.getInstance().setNumExecutors(0); - Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave agent1 = createAgent(j, "agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); AxisList axes = new AxisList(); TextAxis axis1 = new TextAxis("axis", "axis1 axis2 axis3"); axes.add(axis1); @@ -161,7 +159,7 @@ public void testExecuteMatrixProject() throws Exception { project2.setAxes(axes2); project2.setAssignedNode(agent1); j.buildAndAssertSuccess(project2); - Slave agent2 = createAgent("agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); + Slave agent2 = createAgent(j, "agent2", new File(j.getInstance().getRootDir(), "workspace2").getPath()); agent1.toComputer().setTemporarilyOffline(true, null); project1.setAssignedNode(agent2); j.buildAndAssertSuccess(project1); @@ -195,11 +193,11 @@ public void testExecuteMatrixProject() throws Exception { agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis2").length(); sizeAxis3 += getSize(readFileList(fileAxis3)) + new File( agent2.getWorkspaceFor(project1).getRemote() + "/axis/axis3").length(); - assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals(size, project1.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix job workspace disk usage does not return right size."); // configurations - assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals(sizeAxis1, project1.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + assertEquals(sizeAxis2, project1.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + assertEquals(sizeAxis3, project1.getItem("axis=axis3").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); // project 2 file = new File(agent1.getWorkspaceFor(project2).getRemote(), "fileList"); fileAxis1 = new File(agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis1", "fileList"); @@ -209,33 +207,33 @@ public void testExecuteMatrixProject() throws Exception { agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis1").length(); sizeAxis2 = getSize(readFileList(fileAxis2)) + new File( agent1.getWorkspaceFor(project2).getRemote() + "/axis/axis2").length(); - assertEquals("Calculation of matrix job workspace disk usage does not return right size.", size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals(size, project2.getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix job workspace disk usage does not return right size."); // configurations - assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); - assertEquals("Calculation of matrix configuration workspace disk usage does not return right size.", sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace()); + assertEquals(sizeAxis1, project2.getItem("axis=axis1").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); + assertEquals(sizeAxis2, project2.getItem("axis=axis2").getAction(ProjectDiskUsageAction.class).getDiskUsageWorkspace(), "Calculation of matrix configuration workspace disk usage does not return right size."); } @Test - public void testDoNotCalculateUnenabledDiskUsage() throws Exception { + void testDoNotCalculateUnenabledDiskUsage(JenkinsRule j) throws Exception { FreeStyleProject projectWithoutDiskUsage = j.getInstance().createProject(FreeStyleProject.class, "projectWithoutDiskUsage"); FreeStyleBuild build = projectWithoutDiskUsage.createExecutable(); DiskUsageProjectActionFactory.DESCRIPTOR.disableWorkspacesDiskUsageCalculation(); BuildDiskUsageCalculationThread calculation = AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for build should not be counted.", 0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); + assertEquals(0, projectWithoutDiskUsage.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0, "Disk usage for build should not be counted."); DiskUsageProjectActionFactory.DESCRIPTOR.enableWorkspacesDiskUsageCalculation(); } @Test @LocalData - public void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress() throws Exception { + void testDoNotExecuteDiskUsageWhenPreviousCalculationIsInProgress(JenkinsRule j) throws Exception { WorkspaceDiskUsageCalculationThread testCalculation = new WorkspaceDiskUsageCalculationThread(); DiskUsageTestUtil.cancelCalculation(testCalculation); FreeStyleProject project = j.getInstance().createProject(FreeStyleProject.class, "project1"); TestDiskUsageProperty prop = new TestDiskUsageProperty(); project.addProperty(prop); - Slave agent1 = createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); + Slave agent1 = createAgent(j, "agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath()); prop.putAgentWorkspace(agent1, agent1.getWorkspaceFor(project).getRemote()); Thread t = new Thread(testCalculation.getThreadName()){ @@ -251,26 +249,26 @@ public void run() { t.start(); Thread.sleep(1000); testCalculation.doRun(); - assertEquals("Disk usage should not start calculation if preview calculation is in progress.", 0, project.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); + assertEquals(0, project.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0, "Disk usage should not start calculation if preview calculation is in progress."); t.interrupt(); } @Test @LocalData - public void testDoNotBreakLazyLoading() throws Exception { + void testDoNotBreakLazyLoading(JenkinsRule j) throws Exception { AbstractProject project = (AbstractProject) j.getInstance().getItem("project1"); project.isBuilding(); int loadedBuilds = project._getRuns().getLoadedBuilds().size(); - assertTrue("This test does not have sense if there is loaded all builds", 8 > loadedBuilds); + assertTrue(8 > loadedBuilds, "This test does not have sense if there is loaded all builds"); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertTrue("WorkspaceCalculation should not cause loading of builds (only if the plugin is used for first time).", project._getRuns().getLoadedBuilds().size() <= loadedBuilds); + assertTrue(project._getRuns().getLoadedBuilds().size() <= loadedBuilds, "WorkspaceCalculation should not cause loading of builds (only if the plugin is used for first time)."); } @Test @LocalData - public void testDoNotCalculateExcludedJobs() throws Exception { + void testDoNotCalculateExcludedJobs(JenkinsRule j) throws Exception { List excludes = new ArrayList<>(); excludes.add("excludedJob"); DiskUsageProjectActionFactory.DESCRIPTOR.setExcludedJobs(excludes); @@ -291,14 +289,14 @@ public void testDoNotCalculateExcludedJobs() throws Exception { j.buildAndAssertSuccess(includedJob); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertEquals("Disk usage for excluded project should not be counted.", 0, excludedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0); - assertTrue("Disk usage for included project should be counted.", includedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize() > 0); + assertEquals(0, excludedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize(), 0, "Disk usage for excluded project should not be counted."); + assertTrue(includedJob.getProperty(DiskUsageProperty.class).getAllWorkspaceSize() > 0, "Disk usage for included project should be counted."); excludes.clear(); } @Test @LocalData - public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { + void testDoNotCountSizeTheSameWorkspaceTwice(JenkinsRule j) throws Exception { FreeStyleProject job = j.getInstance().createProject(FreeStyleProject.class, "project1"); Slave agent1 = DiskUsageTestUtil.createAgent("agent1", new File(j.getInstance().getRootDir(), "workspace1").getPath(), j.getInstance(), j.createComputerLauncher(null)); job.setAssignedLabel(agent1.getSelfLabel()); @@ -309,8 +307,8 @@ public void testDoNotCountSizeTheSameWorkspaceTwice() throws Exception { long size = getSize(readFileList(file)) + agent1.getWorkspaceFor(job).length(); WorkspaceDiskUsageCalculationThread calculation = AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); calculation.execute(TaskListener.NULL); - assertFalse("Disk usage should be counted correctly even for one workspace.", size > job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces()); - assertEquals("Disk usage should be counted only one times for the same workspace.", size, job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces(), 0); + assertFalse(size > job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces(), "Disk usage should be counted correctly even for one workspace."); + assertEquals(size, job.getAction(ProjectDiskUsageAction.class).getAllAgentWorkspaces(), 0, "Disk usage should be counted only one times for the same workspace."); } @TestExtension diff --git a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java index 498cfeb9..1b1e5372 100644 --- a/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/project/integration/DiskUsagePostBuildCalculationTest.java @@ -1,51 +1,49 @@ package hudson.plugins.disk_usage.project.integration; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import hudson.matrix.MatrixProject; import hudson.model.AbstractBuild; import hudson.model.FreeStyleProject; import hudson.plugins.disk_usage.BuildDiskUsageAction; import hudson.plugins.disk_usage.project.DiskUsagePostBuildCalculation; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; /** * * @author Lucie Votypkova */ +@WithJenkins public class DiskUsagePostBuildCalculationTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - @Test - public void testDiskUsageIsCalculated() throws Exception { + void testDiskUsageIsCalculated(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); - assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); + assertTrue(build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0, "Disk usage of build should be calculated."); } @Test - public void testDiskUsageIsNotCalculatedTwoTimes() throws Exception { + void testDiskUsageIsNotCalculatedTwoTimes(JenkinsRule j) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); - assertTrue("Disk usage called by listener should be skipped.", build.getLog(10).contains("Skipping calculation of disk usage, it was already done in post build step.")); + assertTrue(build.getLog(10).contains("Skipping calculation of disk usage, it was already done in post build step."), "Disk usage called by listener should be skipped."); } @Test - public void testDiskUsageCalculationForMatrixProject() throws Exception { + void testDiskUsageCalculationForMatrixProject(JenkinsRule j) throws Exception { MatrixProject project = j.jenkins.createProject(MatrixProject.class, "project"); project.getPublishersList().add(new DiskUsagePostBuildCalculation()); j.buildAndAssertSuccess(project); AbstractBuild build = project.getLastBuild(); - assertTrue("Disk usage of build should be calculated.", build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0); + assertTrue(build.getAction(BuildDiskUsageAction.class).getDiskUsage() > 0, "Disk usage of build should be calculated."); } From 566652dd3da5c8526179a687531da0f9f33f1adf Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 01:15:22 +0000 Subject: [PATCH 144/158] Add entry for migrating tests to JUnit5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f7b9dce..d46b578a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [Test with Java 25](https://github.com/jenkinsci/disk-usage-plugin/pull/101) - [Automate dependency updates](https://github.com/jenkinsci/disk-usage-plugin/pull/103) - [Use most recent parent pom 6.2111.v8b_6a_1d599df3](https://github.com/jenkinsci/disk-usage-plugin/pull/104) + - [Migrate tests to JUnit5](https://github.com/jenkinsci/disk-usage-plugin/pull/102) ### Release 1.3 (2024-11-19) From dca072822b96e75e65db5e27318ad021262a9446 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 01:36:45 +0000 Subject: [PATCH 145/158] Ban JUnit 4 imports To prevent regressions when adding new tests, jenkinsci/plugin-pom#1178 introduced a new flag that enables a Maven Enforcer rule banning org.junit.* imports while allowing org.junit.jupiter.*. With this change, the build will fail if any org.junit.* imports are introduced. --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index ec94c3bd..03412b4c 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,7 @@ 2.479 ${jenkins.baseline}.3 2545.va_5c4d760c7ef + false From 085e6fc298aadaec0d015e1976de13b036f83793 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 13:30:50 +0000 Subject: [PATCH 146/158] Add entry to CHANGELOG for JUnit 4 ban --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d46b578a..0af9f5cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [Automate dependency updates](https://github.com/jenkinsci/disk-usage-plugin/pull/103) - [Use most recent parent pom 6.2111.v8b_6a_1d599df3](https://github.com/jenkinsci/disk-usage-plugin/pull/104) - [Migrate tests to JUnit5](https://github.com/jenkinsci/disk-usage-plugin/pull/102) + - [Ban JUnit 4 imports](https://github.com/jenkinsci/disk-usage-plugin/pull/105) ### Release 1.3 (2024-11-19) From b06f232248a1c54281f13c80d7c04785f9096f65 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 18:11:42 +0000 Subject: [PATCH 147/158] Removes unused dependency on junit plugin --- pom.xml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 03412b4c..728ab412 100644 --- a/pom.xml +++ b/pom.xml @@ -52,17 +52,13 @@ mailer - org.jenkins-ci.plugins - matrix-project - test + io.jenkins.plugins + jakarta-mail-api org.jenkins-ci.plugins - junit - - - io.jenkins.plugins - jakarta-mail-api + matrix-project + test org.jenkins-ci.plugins From 6609a492206f4407803ce0b191cf7cf86489964b Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sat, 10 Jan 2026 18:40:30 +0000 Subject: [PATCH 148/158] Add entry for removing unused junit plugin dependency --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0af9f5cc..43e40ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [Use most recent parent pom 6.2111.v8b_6a_1d599df3](https://github.com/jenkinsci/disk-usage-plugin/pull/104) - [Migrate tests to JUnit5](https://github.com/jenkinsci/disk-usage-plugin/pull/102) - [Ban JUnit 4 imports](https://github.com/jenkinsci/disk-usage-plugin/pull/105) + - [Removes unused dependency on junit plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/107) ### Release 1.3 (2024-11-19) From 89534116d41d987077f772493a669ebed3b2c475 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 11 Jan 2026 21:27:20 +0000 Subject: [PATCH 149/158] Require 2.504.3 as minimum Jenkins version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 728ab412..c14213d3 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ - 2.479 + 2.504 ${jenkins.baseline}.3 2545.va_5c4d760c7ef false @@ -40,7 +40,7 @@ io.jenkins.tools.bom bom-${jenkins.baseline}.x - 5054.v620b_5d2b_d5e6 + 5888.vd99c2b_38128d pom import From f677e0c24129ec46d8f0b2acf2dfae48ba30afa3 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Sun, 11 Jan 2026 21:47:11 +0000 Subject: [PATCH 150/158] Increase tolerance of unit test for testScheduledExecutionTime --- .../hudson/plugins/disk_usage/DiskUsageCalculationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 44f22d72..2f2b0485 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -49,7 +49,7 @@ void testScheduledExecutionTime() throws Exception { calculation.setCron(minute + " * * * *"); calculation.reschedule(); expectedNextExecution = calendar.getTimeInMillis(); - assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should be changed"); + assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 120_000, "Scheduled time of disk usage calculation should be changed"); } From f87467cce72f12dd7954d052e1579b0abf4a7921 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 12 Jan 2026 00:55:38 +0000 Subject: [PATCH 151/158] Fix assertions with longs and deltas This was using a cast to float and loosing precision failing unit tests. --- .../disk_usage/DiskUsageCalculationTest.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java index 2f2b0485..abea8f0a 100644 --- a/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java +++ b/src/test/java/hudson/plugins/disk_usage/DiskUsageCalculationTest.java @@ -4,6 +4,7 @@ */ package hudson.plugins.disk_usage; +import static org.junit.jupiter.api.AssertionFailureBuilder.assertionFailure; import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Duration; @@ -14,6 +15,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import jenkins.util.Timer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; /** @@ -28,7 +30,7 @@ public class DiskUsageCalculationTest { * see @testReschedule() */ @Test - void testScheduledExecutionTime() throws Exception { + void testScheduledExecutionTime() { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -39,9 +41,9 @@ void testScheduledExecutionTime() throws Exception { calculation.getLastTask().cancel(); } long expectedNextExecution = calendar.getTimeInMillis(); - assertEquals(0, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should 0, because calculation is not scheduled"); + assertCloseEnough(0, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should 0, because calculation is not scheduled"); Timer.get().schedule(calculation.getNewInstance(), calculation.getRecurrencePeriod(), TimeUnit.MILLISECONDS); - assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should be in 10 minutes"); + assertCloseEnough(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 60000, "Scheduled time of disk usage calculation should be in 10 minutes"); // scheduled time should be changed if configuration of cron is changed calendar.add(Calendar.MINUTE, 10); @@ -49,7 +51,7 @@ void testScheduledExecutionTime() throws Exception { calculation.setCron(minute + " * * * *"); calculation.reschedule(); expectedNextExecution = calendar.getTimeInMillis(); - assertEquals(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 120_000, "Scheduled time of disk usage calculation should be changed"); + assertCloseEnough(expectedNextExecution, calculation.scheduledLastInstanceExecutionTime(), 120_000, "Scheduled time of disk usage calculation should be changed"); } @@ -65,7 +67,7 @@ void testGetRecurrencePeriod() { TestDiskUsageCalculation calculation = new TestDiskUsageCalculation(minute + " * * * *"); long period = calculation.getRecurrencePeriod(); long expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 minutes"); + assertCloseEnough(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 minutes"); // for hours calendar = new GregorianCalendar(); @@ -76,7 +78,7 @@ void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation("0 " + hour + " * * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 hours."); + assertCloseEnough(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 hours."); // for days calendar = new GregorianCalendar(); @@ -85,7 +87,7 @@ void testGetRecurrencePeriod() { calculation = new TestDiskUsageCalculation(calendar.get(Calendar.MINUTE) + " " + calendar.get(Calendar.HOUR_OF_DAY) + " " + day + " * *"); period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); - assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 days."); + assertCloseEnough(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 days."); // for months calendar = new GregorianCalendar(); @@ -95,7 +97,7 @@ void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); + assertCloseEnough(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); // day of week calendar = new GregorianCalendar(); @@ -105,7 +107,7 @@ void testGetRecurrencePeriod() { period = calculation.getRecurrencePeriod(); expectedPeriod = calendar.getTimeInMillis() - System.currentTimeMillis(); calendar.setTimeInMillis(System.currentTimeMillis() + period); - assertEquals(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); + assertCloseEnough(expectedPeriod, period, 60000, "Disk usage calculation should be executed accurately in 2 months."); } @@ -116,7 +118,7 @@ void testGetRecurrencePeriod() { * see @testScheduledExecutionTime() */ @Test - void testReschedule() throws Exception { + void testReschedule() { GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, 10); int minute = calendar.get(Calendar.MINUTE); @@ -128,7 +130,7 @@ void testReschedule() throws Exception { calculation.setCron(minute + " * * * *"); calculation.reschedule(); // should cancel this calculation and schedule new instance - assertEquals(calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000, "A new calculation should be scheduled with a new scheduled time."); + assertCloseEnough(calendar.getTimeInMillis(), calculation.scheduledLastInstanceExecutionTime(), 60000, "A new calculation should be scheduled with a new scheduled time."); } @@ -153,4 +155,13 @@ void testTaskIsScheduledOnlyOneTimesPerMinute() throws Exception { TestDiskUsageCalculation.stopLoadInstancesHistory(); } + static void assertCloseEnough(long expected, long actual, int delta, @Nullable String message) { + if (!((expected == actual) || Math.abs(expected - actual) <= delta)) { + assertionFailure() // + .message(message) // + .expected(expected) // + .actual(actual) // + .buildAndThrow(); + } + } } From 71a58331228c93e51beb23d05ce7b29c03bc079d Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 12 Jan 2026 01:22:57 +0000 Subject: [PATCH 152/158] Update CHANGELOG to require minimum Jenkins version --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43e40ca0..2bf92536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - [Migrate tests to JUnit5](https://github.com/jenkinsci/disk-usage-plugin/pull/102) - [Ban JUnit 4 imports](https://github.com/jenkinsci/disk-usage-plugin/pull/105) - [Removes unused dependency on junit plugin](https://github.com/jenkinsci/disk-usage-plugin/pull/107) + - [Require 2.504.3 as minimum Jenkins version](https://github.com/jenkinsci/disk-usage-plugin/pull/108) ### Release 1.3 (2024-11-19) From bf6f750dc567842c5091f14b2454e97dab42a774 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Feb 2026 20:08:00 +0000 Subject: [PATCH 153/158] Enable incrementals https://www.jenkins.io/doc/developer/plugin-development/incrementals/ --- .mvn/extensions.xml | 7 +++++++ .mvn/maven.config | 2 ++ pom.xml | 13 ++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .mvn/extensions.xml create mode 100644 .mvn/maven.config diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 00000000..9440b180 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.13 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 00000000..2a0299c4 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals diff --git a/pom.xml b/pom.xml index c14213d3..d94b530a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - 1.4-SNAPSHOT + ${revision}${changelist} https://github.com/jenkinsci/disk-usage-plugin @@ -21,13 +21,16 @@ - scm:git:https://github.com/jenkinsci/disk-usage-plugin.git - scm:git:git@github.com:jenkinsci/disk-usage-plugin.git - https://github.com/jenkinsci/disk-usage-plugin - HEAD + scm:git:https://github.com/${gitHubRepo}.git + scm:git:git@github.com:${gitHubRepo}.git + https://github.com/${gitHubRepo} + ${scmTag} + 1.4 + -SNAPSHOT + jenkinsci/disk-usage-plugin 2.504 ${jenkins.baseline}.3 From 5269a8d16adb0fd0f05244424142eba089a39592 Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Thu, 12 Feb 2026 20:53:53 +0000 Subject: [PATCH 154/158] Enable continuous delivery https://www.jenkins.io/doc/developer/publishing/releasing-cd/ --- .github/workflows/cd.yaml | 54 +++++++++++++++++++++++++++++++++++++++ .mvn/maven.config | 1 + pom.xml | 5 ++-- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/cd.yaml diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml new file mode 100644 index 00000000..9b134d5c --- /dev/null +++ b/.github/workflows/cd.yaml @@ -0,0 +1,54 @@ +# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins +# +# Please find additional hints for individual trigger use case +# configuration options inline this script below. +# +--- +name: cd +on: + workflow_dispatch: + inputs: + validate_only: + required: false + type: boolean + description: | + Run validation with release drafter only + → Skip the release job + # Note: Change this default to true, + # if the checkbox should be checked by default. + default: false + # If you don't want any automatic trigger in general, then + # the following check_run trigger lines should all be commented. + # Note: Consider the use case #2 config for 'validate_only' below + # as an alternative option! + check_run: + types: + - completed + +permissions: + checks: read + contents: write + +jobs: + maven-cd: + uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 + with: + # Comment / uncomment the validate_only config appropriate to your preference: + # + # Use case #1 (automatic release): + # - Let any successful Jenkins build trigger another release, + # if there are merged pull requests of interest + # - Perform a validation only run with drafting a release note, + # if manually triggered AND inputs.validate_only has been checked. + # + validate_only: ${{ inputs.validate_only == true }} + # + # Alternative use case #2 (no automatic release): + # - Same as use case #1 - but: + # - Let any check_run trigger a validate_only run. + # => enforce the release job to be skipped. + # + #validate_only: ${{ inputs.validate_only == true || github.event_name == 'check_run' }} + secrets: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} diff --git a/.mvn/maven.config b/.mvn/maven.config index 2a0299c4..f7daf60d 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1,2 +1,3 @@ -Pconsume-incrementals -Pmight-produce-incrementals +-Dchangelist.format=%d.v%s diff --git a/pom.xml b/pom.xml index d94b530a..cf070ca5 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ disk-usage hpi Jenkins disk-usage plugin - ${revision}${changelist} + ${changelist} https://github.com/jenkinsci/disk-usage-plugin @@ -28,8 +28,7 @@ - 1.4 - -SNAPSHOT + 999999-SNAPSHOT jenkinsci/disk-usage-plugin 2.504 From 48e491998f30c0a562e5cf781378e50933d5b81b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:39:09 +0000 Subject: [PATCH 155/158] Bump io.jenkins.tools.bom:bom-2.504.x Bumps [io.jenkins.tools.bom:bom-2.504.x](https://github.com/jenkinsci/bom) from 5888.vd99c2b_38128d to 5983.v443959746f1f. - [Release notes](https://github.com/jenkinsci/bom/releases) - [Commits](https://github.com/jenkinsci/bom/commits) --- updated-dependencies: - dependency-name: io.jenkins.tools.bom:bom-2.504.x dependency-version: 5983.v443959746f1f dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cf070ca5..37ebd5a3 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ io.jenkins.tools.bom bom-${jenkins.baseline}.x - 5888.vd99c2b_38128d + 5983.v443959746f1f pom import From 6373189a7a33c3f7d8d0c3d7af74336b61fa6ecc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 00:38:56 +0000 Subject: [PATCH 156/158] Bump org.jenkins-ci.plugins:plugin Bumps [org.jenkins-ci.plugins:plugin](https://github.com/jenkinsci/plugin-pom) from 6.2111.v8b_6a_1d599df3 to 6.2138.v03274d462c13. - [Release notes](https://github.com/jenkinsci/plugin-pom/releases) - [Changelog](https://github.com/jenkinsci/plugin-pom/blob/master/CHANGELOG.md) - [Commits](https://github.com/jenkinsci/plugin-pom/commits/6.2138.v03274d462c13) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin dependency-version: 6.2138.v03274d462c13 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 37ebd5a3..00a0afb5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 6.2111.v8b_6a_1d599df3 + 6.2138.v03274d462c13 disk-usage From 1bfdd85e959a00d7820f7a6e720200d74d19473e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 00:47:36 +0000 Subject: [PATCH 157/158] Bump org.jenkins-ci.plugins:plugin Bumps [org.jenkins-ci.plugins:plugin](https://github.com/jenkinsci/plugin-pom) from 6.2138.v03274d462c13 to 6.2153.vcf31911d10c4. - [Release notes](https://github.com/jenkinsci/plugin-pom/releases) - [Changelog](https://github.com/jenkinsci/plugin-pom/blob/master/CHANGELOG.md) - [Commits](https://github.com/jenkinsci/plugin-pom/compare/6.2138.v03274d462c13...6.2153.vcf31911d10c4) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin dependency-version: 6.2153.vcf31911d10c4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 00a0afb5..2f2248b2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 6.2138.v03274d462c13 + 6.2153.vcf31911d10c4 disk-usage From 7408b05afd0af417f54c647e73e50027529b71e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 01:11:02 +0000 Subject: [PATCH 158/158] Bump org.jenkins-ci.plugins:plugin Bumps [org.jenkins-ci.plugins:plugin](https://github.com/jenkinsci/plugin-pom) from 6.2153.vcf31911d10c4 to 6.2189.v695a_c41f5249. - [Release notes](https://github.com/jenkinsci/plugin-pom/releases) - [Changelog](https://github.com/jenkinsci/plugin-pom/blob/master/CHANGELOG.md) - [Commits](https://github.com/jenkinsci/plugin-pom/commits) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin dependency-version: 6.2189.v695a_c41f5249 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f2248b2..2dd1892e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 6.2153.vcf31911d10c4 + 6.2189.v695a_c41f5249 disk-usage

    OBtz|7Zm07hrhW4(?o2lh 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 VroR+*YJLO%9?2+6=SUg8`#%UIiCO>v literal 0 HcmV?d00001 diff --git a/docs/images/du-overview.png b/docs/images/du-overview.png index bcf6c49ee94c373a59b13ad6eca15887bc7bbe42..eca34efeb92ab1997b6a8dfe6e54256939ad7acc 100644 GIT binary patch literal 157341 zcmeFZcQ~9;*DjujNJNkj1W`he=ygPwh;E1;U7|CCsL_KUA$lF7MDLx^38EWy7)DPR zo#>tOizOwi8?6udr*S+qwKfP3zCA>v->&lfYgz|DP z)UI5)0lISK+T~3=;Ft8btj$-h&|i^%@l4~L;rjHAclSooo!e6QOqDNjhCQ|#^XMOc zH?r~zeoPN~A$eEzr3NnhtH~uu=O8vtR zTVAxZ^srjK-3cUTpWQ$$<%@;D<95j_S8?zB+dspFl6a2hxNxh3`T1}Ee&`)Z$?G>k zZnX68ui)JLH-97(Dd@+Qc8Tw@eEjzVui)UqMQ{9VQhFr89Z2?Z&_~i2e|sB0aLToR zx3XW$iNFFcF>)sL4WHpJ@9~v`0K{j}!!9H$#^iy3M2To~;u8>5gv-p=H!wYY^ulFJ zdAwvFX6>FBDo8nIn*v;Qd~OF!z5 z{7lKG08`6qXH%iYCnAbchUzL*vtZvj04x!EUCL{Ry$7k;L7sZOJUX5Onb zzsiQ@EQoHs0$wA=Ao!h!{CL$%eByd$!B)n6kh5u5#IvR(VeRaTo$3eTE}!lByu`L@ zsD5u(a_L{=IP`7`L|b-Xfp6`OLuETwY#_2v)D^iY=c_>gDuBJL2(pTd;BhqH7OB$? zBwBy+I?dPN+*+>T=ZFPYY^2dZOj~F8bR_W|iqJopkLB9LP=@R^U*MlJt$b<4+`CYD z>LYtX4i44TlKHssx)f}qt6;3>@lMFr_K%&;J=G{N^@Ji+-$Eo91exS=&X4)X1nXuD zIos=0pyaa(v{Lm@z`@~~p1~xE{lT;&ZePt8i1zK^1m0>DM+2HId`#miS$zXumu-H` zYqscngEoR{)TS$+OwqKpv!tskLK44;c?VN(lJ$Jz`;KWnRxQ(b#*+AJ9^cjP9;=lQ z{+1>5$Pz3c`NMVU+PCYBe=tTt+o>y8e;E!3u2bGKJe*Audyi6>V0gUK8b)(xiHqK1 zAUQgOC9JpRZsUe~q7UaJgINe!MDSuT%R8?|ywFJ4E=9$dxt|*34->3_-y8Eailyrl zwtR6g@Q_9hk; z#mM@dP6r`3Y&ryk&^COxtB&7Dl1M%^j1tms^3-uy=$hY4q5?r4uc1p+c8-beb4ym* z`5dfIn2iF)jj#;N@^eS(Z82my$QI1u-#<$d)0XGTE~SL1+(5B zF^;YH0__srAGcY;yGw~Zq<6rAGUP6?FQIH+B0|O~~yeiQi5`eRZ_Z*dN&%u+zKv#Td4IN@Df0AnNSr zxv0>b>u@2G@@`a}_2>IM&+&*JB;>9%G&U|KS>?gWJ8RzlSXhiV3UjgU#s@WDoY=U{ z2T-IVD@;0x@>DZqbQ>W3_`iz-zD`_{rLax9H=K8Tofsuc-E3%kEK=NL>Rh*MiN&2) zHDDkprby_nAl)cOi#b*amgTbjop+zp&aDMES_nPmgT_QBLwQF)BeNklB#&;wc7 zj=aBdhJa2ow*?W$bLb(uA{k{L6+j2* zFRaNZh9p?b9*A+3kIF7o=`fsFxDs)3aZ#JE4*O*(#0IFhmxFz4W?Xtb~95^ zTt>8cT181yjw;Fb3{Hw}fdo)Vyk@~-t{ij2`Rxn033;n;lW*@R_0I?%ZWEK|ou_%U zf(dzyy!JJRY{u;Qn$ps;bv?J+DbinCJeQI}O5}s0reI)#v3s8t(IxVe1~vw?wsoT8 zeQ^SCCsv*3;`{wE+x~< zgk!d`56s2-wUvz`1X#`=?FFwz8ye`Tp%Xp}r+DtjA0IEJk~*$dJ5g)n!NUlKDCjSS zoD}J_h{ApwP7as#j~)!3CZDjGFExF8@cm?;yE{op{SBzGs2ZQ|x(uw3#PRbUll{&D zWwi4d2MhSBE{wN5({jiUG>A&Oy7Yh~&1^9+e%d$9JnZdfgB{jM6tuG~QN4y-xGfukG3$+MuRZl4Y2)co_PCsH*ZV5H|ex;3JghIV-`n=I3n^$PfxI1Jgy zddQ>A3aaHJpC4x`2F3BZEaR@&uYX83>5R4E-P?1UaOM5JRr~-KUW_v3{C(uM4|vZO zObmjIvx~TH#ue&R$i=e8W@;5t6+f+-v<_2@=j`o?)ysV5Z~Yw_>=?y+c7Dz5{DdYu zv8Y&a(uH~Pftrb)S22fClWI>K2WNZ8Y%EpK!u>q@(${UAFri&LYEx^=yzr8Wx62XX zgc1VFp5H%>sWp3#K1wyPz5(Butd0j_x(KvAznA#p;&e;CE-)lR&9G?Y=@&#g2Q**8 zKtO-n@XHd(tVw09%kDjG8{uN@$zjlJQ;%l6-O^jD(mWfRixQ_Nu$PaU^|?nAh5Pl1 z<6V`)u?ma9irEi@Oi>XtB(yF97-`e4``h^Ogn9?#e7A^*$OhIY9%+ZI^KQ*n4L7KQ zkN105hDG!)=_sN|TwJ`|dX%+( zb8)Olk8z+;zt+KF?(5YY;!Ing0kK25(2BSV7Gvt89~MV-xpz-h6PY(B;GgqbFX~yA)aK>CtQo`y}g?oC2;rj+{eR4nTA5 zBO~fKI5_K7Yb-bSf{JX=#cJiI@;OW06nB4z^5w#Dp47rZ+LtRzCfW) zm30WewFaYnOZG|0tFj^X=~zuFPy^-7HBTzsWC=QYUF6CNY!tDJvf1Aj;y68^2|e7S z^**BAeWlNT7=GAIraqW)C?O`wE8m|al=-U6Pc8k$eAkuM&ZU^?Vz=Fs4!*b3cTH&Z zw;C@`w}kTy8yoO_gI{>-=|vUmR7`6ulSN>v*x;vSL5oLkB^*-`zNXz#~ zVmP{aLe?l^wGu;3EA(a)uD{!PZL)}K9%QPfcj2Bvw0UI9t=32)lLsSz!tqV zzG_&Uz*R^px$SO+ZMO#~^6q{}g>_b~i8Bj~KX_{YrQ!18)P33_Ebz|8%gDliKs;ng9B%^CSRby5V+BPn=g@Y-yg)`dq?PzX_*&$|)@ z4*VMFJb(H&oNm^arQF274j0z;$0IZau$kHy$*c93NkWe6CuzWJC4_hBy!KSx7Gt$D zWkQ!z$AEB@>{em7Ft&@ff7PZ(^TQH}}N$CY(lXmt0>OCVk7Ru8b(-w0otA8Ol=L^WAVX>4tFjovq+-KH^R|9q zE=+K@Zk5veH-YtjNP5STi{?v2!f9y==;!F^FuKGj-seKc;+9)5?9IJkrK$4>JHv88Hiv zOohIas5+IT7V{7~u(Q@)*6j@*obcc?H6(8GGi8_>-?-B_%U()kl5xdgsc%$;bMGs3 zZW?yGp9}M4WI}GF#k}ZE`(i=;Erpc6GL`evPDntDNN%OK~>nryXcwxn}oaVqbtpYI3M)$yJ6ZC0OLTau0E$$z&!j zJVPdwgu}$;_6D?2GhDdRdUtPS1Utg6!_ZtpP#Z=g0@~T4;!F{B8^&`BOH)A@)Vs*1 zihC(3euz~oHGZ}mPEgTrIb9by`5_pIt14p~oP z%N1gIIbkEQ(T@bj^{Z{`m+PXziKy}%(xG9OilTnh9lllfn3GpR1cX?m-X@Bv_^U&2 zTqES(9yDynvfa}{QRfxWNLUqDwU%7jj0v+Ea-pBWy0 zLfry&ex_thtbb&Fn?@K#p2uYVjS>KD)^S4hgp z%7|j=ikk}K6Mm;J`U%|9&p}YqfqH6%3-P-`VY6#n@;`g3luIPQH{eJm;fsu8(_o*N zxH8p}?_%m5#}h}y-$X3%POV};N%U2dC582Xr(Gsii^>PsmG!FKujgr3_<8bTZ{Qo& z8>ED*73EDPgUrrLj*_FNSr~BCv_rq)!7(l%>q)I52Gkd>RS9mF_3_t+xJn9_ms0-9 zP(5l|TH50(uhRn<0+)>8ve-9$^T*Z}-EkF=VkA(cNTeI2YY8f+hzeoQBmmreV9@Zc zY$g1>g3z=?zm|k$637nHHKD=;AZH8h z5Jh1xnd#@spU?|gvN1cuxQgx-=~V|C2)@)C!gfdVIYK9*5IaZwxvoDk#i~Y6WKtbqv(AR;QS22S^VT#eBDaSYZ4c&vrp1sn530y7pO6_mJ|{;q>m#YwP;`82VLaV_hWS^;i6yN*SCV*cyRWAZ0z zUBw%e&dZ=V^sUO1u;1uCI3v^I`!V-L`(w0v0MgGZeb$7RI8JC6GDa%m{8KsGFizhas@ z_EYEvf+r|2M|gJH6&(kBwn;l1&3uHdvxYr09%o()Hj@AKb)uetDDEht>iINtmrWQm^G$ zTiT23Xa4#-Cv;Q5j@Qj>_rQyHyYsr*w{>)1!%)EW>%C1T-sQt*UvOc(N1oSjg=l94 zEiCK^sY$SF7!Ek@UPm;}x(PY0Tc-OYkW{>W;|DJ46LrLX9&y3Jr;(BnD}B=*+=V0| zy-m)h)z@Hk`~rT`Ml2EII`ip*II0FXDH%J5vp#}$3qp|C?BcarkHgJ(Dx6jJYj~wYG<#F#;?!nlLIz9Gmu(R*(#hZe$*Z7F@7|!cD33Fu5w- zS%Z13#7F>h5+COEfWw&1v-A_8k-($#-GNwyJ8&xC(roziO!pwxY_AASs??JMYwBI; zDm5#0$?|=bo)=l}H$0&E>9Q$mJTUUsn~KP$USGC78?S>(zhiNuCJtD@xHCn876*KA zar>PA@fY94`YmrVJ2oBJ+&r=_9=)MeCL!GkBDxtC%t_L=f$f`X-(sSe_MLgkmSS^_ zD)}#5`Bq8jkR1nTYOI5&7#--ku)MiUE4prcjo-T zjBJk>F^$ED4I2|gsdJ%D-qjF1AB>t-P=&GjHE^dW&o!0lPMy-ctFuNvMddbr*894B zX=}GPXS`m~x-A$|a|RY5g8z0=j`GgOux?UvS>9J?I zwRfyiy0Y-P$1b05lKpOX;y@*x7%OjmliYIcQ#uuZw$TkRDmR^iHqp#OJ+~-3!)W;E zKu^e)j%f=oB^w5i?2El}L))qH9ip`hC*A7bM;gOF+<4(M?F1TjDxE+XEAz+33*#Bq zuzOE91iMxcF%LFyK8)}0jr{`mHGEAxLPdX+wD;8cd9X)_)b=ZIQIJI)ArLNL;Of3-W1kUE`48=Y9F@nqZXO<3|Y4dmqbctVAVjMel+ zT$U0b1yXL)iHj=NqliHJFDgk~hBM`NmNUXTP7?wH0w$U!blbasm)1+pDc_L;Xg|&Y ziCJ0NcVB9CQu3qKv#V#Q-mvc6Qk-q#str|T;}^7>;h32@h6H@kaITRggV7WK{+TKBYGAg!L%) ze!ixwFkE`=b~Nw7z$WR8L;}g7+(>p6$wnN2>PKU#&a6Xb#5}^rt$TBAf|&vLp{HZO zr5=Ph&@8z{rZCZLla&`3uZkY;i|48~kQynBu_%#}`jH^Tv77MI&zNtB*fDXEyI89- zj1;_lTA3cY9f4)#*jW~igv>BJV@^G3E8KQldD#$N4=}hJ{S(Co_4mXE_(^SM#W!z_ z9Qh&pq&K79sCOu2H<%Y8`If#_FReM8e=urTiq7^&Qn`}FJqu`rN}I*+#%I~vR1kg7 z3Lzn}Z&{Ic)30X`Q(li@o?u|*7V8^MY6HhwMBsn7hNWP$z*c9R-Rx{T@i8_+yC2a_ zguKiuTJ;-s5d}MGvsOZHbX%FtzUlX>7LePZa_`n|E&^#%mLkOng;3Anji=T}D;pb7 zy&)MI3@yFu=9Kx{>A}pTut_$Mz}Hc&O4R`)m6rq6uiFC6BiA^T2LuKD!RNToA{nIn zay~IUU%f@fDwm_2oawwa=0Y>l2g@ia%Af25s7Ybh&7?;*AerCAmN^$PIor}a^kmiA zF7p)R$#k6Ud$wd}B&rn%BnQO2y$;`9DzVq)$mb4| zEYmFLK(wlMp6rW2Pp9HIs1tUPagUn;mw`pD$!aOvj+ZL-C)Zm}t_WjQ9s}{8M6Y_Y zq9q$~8Y-L)qz$yM{O1I05SY26&HA;3wU8R^t^0Lxxmwv;dC%D}FT}d6>@$90*^1y= zm+T)J&gYm0x7}|O=Ag9mWCMpcdQI6eYXP^EKQp`5ImW zbZjb#>2PY~8?J-JhFD8~vdDx2*ltVB;b2`ge(0%gr%bZ_Xg<;f2_^)2AxTX15bFZH zW}4NSN&Ou@m(VJxHMJm!gYMF2`2p2VI|XDlyEopBJ1r%l*v^@>sv~=o)TlJC$Vt0o zh80N3qt381)nSfHXJGmoWO27nwe8}o&bKaLc_5xBIIj#7X7?t?qY5a>JmW?Dz{!W- zr5l?z(#euSsYdxXTp0T=FjZ^mE!lyIy7Ij>V%HxOnR@KIi)t0tQtwZ$p~@Dlp9t@$vnHa@?cY+g0fNSA1X@07cQ@xe{P;`PCm&nG=QVk8 zO;mGxQTmh+Yk~g~XE5_=2DO#Lb`re#sl0gpG;7v{KZtp=zPAt zy3|(=fRv9b!(cSnI0jN0jr}DJn$^%{D4SpWb8R@)qxKLAgpFKaP|yS@Kb9@NY^lQI z@L|2U1yGTJuxZc$Sv!wUSo0h8>X9En<~`B}pPnM-uoP*vf{(3^_KFyos2_gf8b{e2 zoo;C&ifn2f1krP-T_O9qnnq=Vw&6DRv~2X3*f^l_L2l5=yDFzpns+KRb^t-;2D*9f z$l$>jd*kmEK|+Q1UZtc6vdNO_m8~TFINDY(hfa#`Hq_{>vkzigi^rBU}FbWK_vxf{Q$-y9>!{&I?G6mIx z#}fqcpCPL7k*$a+bV0M}PgeTZvcz&7(H@zW+a%@450ljB3l=o5MKmO+y8Fez$M9hG zo3|s&at3<39p7sEb?o<@Ev5RbpCk(Jh3ZfCUmWPYXq`!y4tYi9k0BY|KF@Vrjh6CP zIQK@S`Ob-KHJF^#a79N%+@TIWSQ+WO7^dHwut*I>c=ZJs0(b>d@Hm6W;3ml2y*R4_ zNaDj023s?Yiv=Z3!3P3GB%_W)Lt`3k9T0iyvZqIlWn%>>0jVmcLX-8`=Glfk&Cl(t z`MYTHCf&$db0n49dRZsKBHARxv2XJci_7W!&7h7WjhapQDmmZDVN-s6PC| ztouq!?Wt{3gq{1RIvdSfyOj`xg$QX5?P8z~*WwoovP5xnVh2HGr-yX0it&EyJXHZj zcpu_94G?MhjO1!?PIho~x!w*n8ud}d~+RO}K4 zD?KGb2`uX;R5QFwN1LgPt?QSL0s|B45ZI2;dL^QvQQX7p(M|!IM4)I=Yhg}$o_TY? z^C^xTSLg%OG~;VEo^hpIYrdu%Y-!fuX~E)Otn@R0l_tm;nH~ENbwE_!t+Q?osP{Vo z|0B&tJwGYGM^iCr!ZOUeL4|IOjCv^Zr*B`1mgvXH5F?@=fVU`8VbPi9vA4?Y2i^)% z-e(o;Yclh4?TvTfsLRb?eyoxTd)4j`HtqK2yva4s@dzFVWbE zgjuQf>2B#VJF9GOQe#{={XG@jGoZY@(?M-F-t$t7ju0d;_gPpuRh$E(?$#Z}bfB+SWlgr$;N(%1ki>5l z<#uiV?aHwYHHLtKb6iDv5hz`p{rDc`c`#v-{;)D|fRKv+P7%9v;p_Z|+tst)a8yvr z#&0WmHPGv7jN=+fWNa6F0e9H1lI?y1!mYG=W6kuGPmvj#QE5x6ZNW!LR+=!hYB=ug zDZz4G5ue2cG^M!~OuahxR=imE$=U9J&*UnWCB+h&FT|+(kj1PCSw7(wFmY6=vPRo?Vo$^>A~VE`x+W z68&Z4jlh?YDn4QwVN+e)cL^#4(w;rCoxx;mkkPEbz)zHk_G`isy4!hViBvMylDUpt z`ZX_q6AYKspkNp3?$Z~FSsjViO*p{Zm2epn2vTU4^XI0dbXMuh&2O+ z3~9ZR;j$kNBm^1E zBg>?6TK$1tTZ1PA1wenR2b2@UdD0k}YD;fBA7Gi4Gox&WsdTA)6RY=5!B%ANVB-{A zweIFPQ14q5XO>BPwP@;WC8xQ4V5^W2R2AURStS<@z9Btn_6_Wc;hIA2M57o()eIS{>U55oL3^D?ia{NZ>EjHUimB zBo*d^I~S-9tgh$aIqOp9`oa*;#a!4=62EZnnX~@Z{{mXYZa@|)&+K?iWpfXm|x?2Cq&bu;hggB0G5 zn$PXq44b2Mw;QQehkIT1O7l2g2~71t)TSGp^~Mnul;HZY&)GDqWYL4lN0y~4L56*S zF+834sXun~o2!|gdU#tI^4DwR>9mPottzRoAX2d!&rSP$w(dBYA~5(N?f0+l@T}U9un%L?NBqMqgHOYx^o1B+?dh94&Z^sL{8+=$u&k)5P=5ZHYCd{14-doMSJdp^5ZM5k84OsCNywqdHi`hk!Oe>d?> zkv|E9tD~>9U^n(G-xlATn!u@M9dC#pZER?OB&=Bq7F;d47-k*Y15HsuShbFWH5ZGS zi92tBSO|U8sRV2nQ0o53`7NT@(5u)Hu1-XEl$oL_YAGXgNs%kD>S4u%7xt1zW#<0V zm&&PP(KEE9#W#LOuK~Y(WR@)LCdIjmYfEv}4>`FQStm9yve9B5&?E53wU)|(FC zt+-0Dw_vMrO=Dwl(_p84!K(aZS!jEGfz`A@?ZhXW3PA@^E$+PQs@uN5|d!rEAsx zJWGF)TW87vdM|0u_0Lyu@*V?o%s9?-Y@ZX-1T2FK|oEd(3{g$JB`K3174$HX9>x&OTiu?6H49AaJ%6iy-^qq zn~LZ~&6J0oBcQHCLHqkw{-m(&rdURoq<*Fq6Fw#_W%)J9Eu3F+!#wqz?AFMq-;!DF zdx3JnlxMbwD~$hm?bX4w@?-==s&2HBLT7Sj;Z7o-%57L zDsx?Lr{RIx>2hOrd^kVkQAWq-$iPr4nPBT&O8f2f+cdly*%v?kKN#YJB{2HLB^@OY#vx0-Up$9jc0#23I7~?6*uY$@ZTyub&>kZNM95w zpq>`93H$J0SO2@M>b?gIWPVWpTanIx?#(X|Ha-xjQUqk5|7~j1TX!JLq+!$lTJ`Ur z==TASs6LR$_}8gQ%eDicU8yn(O;*|1_tuZj}!jY)KmcD-7gd(`PAP(M8T=ge(eSkxzFX5?gXBUh2D4-Yg8_) zis*KN=+WG@?gLDdS5PH%QhvtkkRzuBi#GCM1LSKfKsV1ok`Nmq)f5N713Su>*4m(H zbt)~(Dy{e5<6E<_Oor0@Huw5ZPjW|&>(>G-kck|24cl?}ydo1l-O()PrZWu^i{Czx zf+A4Hyh1;e2|%MC?fHZT?j8L5vn*GFV~Y<0s#{j9>~v-37`6TF&QuaYmZd(}lPVi@ zIn*rtfsi%2uh6hD(er1^ojkRya-9s`S9rv<483t2)w66`g$aGhrv(p0-wkR(tgkNv znQHq8U%lwTD_OT)tGI(?+eQS0su&zDFKBjQ zo?Tl2be%E4X~jTI5b1>Y_yVyh&Kq^fKRQA`-3C#xCz$BX88&+xB=TEv2HYa!f3^q# z@Jl42$`bMv+3z~{^&x4*g$hu6)=_^b%#ArdIzEPdEq61$SiXG~! z08DEr1XGDg$tXYrrJCos@D;2@D8XM0+4oo5mCqTEk)hk7v)lgY%y6TJwz~W=0Ff*D z5wW9MWxl??*{g3Wtj-fvXMB8WtaMI;ta#u$DekNC)DG6tnOcxls$@Vi{kd_f&KWKT z*sPM`cwU(w_}n{3StZe>y3_P{M>@Nwyx3`d{FzMHgS+yY2ndji35~Hu((P`h%+`^qCbMG`2iDf!uZJIjo`*_QwTwh3tg|@0z`wQZm0JXi8Jo$ z%A9k3g;-WHw(&ykl01#vm;IIRlgZh}ZxazkW`p6A=S~I#!p>CiU?f8%85|%2`O~m% z0MRrsVYI(05Q#-@#RBeXv>5+n+{6G7(0J^xvV~A^@yxIDZXX=DD3;3S!iv57YwrKs zxZ!*6Rt?km`c!SS6~5kRv5AoDrl*kCiIb@fy2U>zfwec)Y)fi(<}ig9s_z4B>=J+ z&3_%f^~!`#mPn<7b7^`wS5-=#5My9FRr9*Fe`XsG4(QXPfyy5&cqkZq*r{}%ij`5u zbF*9kgfF0eRA}z{@880SWp3EmalW%K+8G(0OY zfbTBIOW+gKbN(vX%r8_7r%8!;01Pg--l&ixmR-o>AW5TGzq_)=t4+gttZX)w=Lf~^ zdH44s%6~*plOAk3+;pZzLPqVYP z^Qqrp74$ipw^*6=iTF$>feD0fhXUlzM3qfR45xuwLnFbXrMJ$f;#`e;`DX`{`V$Cf z=)EUuPsg^S92z%8Cl-6P<$-jo_sg@A-nEiL=cTj+YF~aX`-QH%Fzb9y*9}bUvLn)E z?!AV%vw|V7X8f@u7R5iZY15`8n@hQSc>iIJt;f;24$KyVMx38HT5Ycud=eL@{?j!j z0CRmut^(-IeCfD3mHLka-XhiOp~V1gthkqaO9*!2!a{`5Mum ziZJx{9t4@)#(d_vI*sm{$9p3~kuBL#^^8;cmCHtMt9eU6Yjxdl>1(f{-B;zNwMQo@ zrK8@u`|(qen3n7xx&VX50BHKiC7RU%ra}uy=^8Zh)a0>!$MQRiz3{2thvQ0!2OiSHwf9!sxfSNgkIMdSRh7Yy+;`WZ0ILyK9z-T9rer z0zWJzs4Z-CE4)79OE>ez!UxVy3Jg5>#6GiW7k8ye$(qhKT~n*FHp_dNrteWF5Aw<%cNK&Wq~&*igS6U`w*ME3W4Dmh0)A?Mg)jxOfv^0_P`gGv;{ zCWg(kkE6DPT9IJ5mcl2JcJ)1b;nuJ5hVK0c8^YVSVHrD}iXquCvSqq&Oi;4>e2K^$y}S3SWt1sziVW z!D|3BT;X%gqxc4~t)TClcS-;7*6OvGsmdQ5On^`i;@>6gY~2lLg{UYY;zx7m4rqgb zzFPK5sNLm-M_ADvXI%IyD!skY;pit1K!{ZVWkmG~(2^5%y6E0uM!D4pc`eWu{i02e z@Tp=PJ13hqCxThH^I$_{lnRjO&nx;K zM1TM-3J~&;HWK+E@10wg?m{{3v3-=30@g7A&3gkYuo82A9IjhN$u}-)HZ~{v6q4ZN zz5EbgP%}kPi9p9l8SC52G2jm==CwSfG`^x@x16rQp22R&An` zdXWtDoiOMu@z_qGcP>upq&F2yVeB$4e_~}xm?E%#NPzg72yRMvXr|wiZMdi+fh;Hc z_=F~mn;R<%+=mizyz3KE_{hogGBMATiho%Q=*vwt?F@5f{@iQcT6v<@@J>~y>CCP> zaUUxj7e-&~b1BYi))SuH%H7QV>Sw`-OKJbuIBM`En{019mks6zXX%<(u~D-;t#?g^ z6~_doPlyL&)d}=U%N$N0O8kNXKp+1w-lw+)1HRXSAXf^WZT+0zl7UNLso(%NCNP>P zrX+_^54`Qh#{2HGdvvqolEuQTPdx0sV;R0CaW~&U!=veX2{TqciAu+C+Vj|=*0ZA@ zY1zD$9+kVpchYsM@DO!C1>vspl7!buAtAI%!D%R60%EqbvsjR+o|A(QQa@>Hxu~xC z8uLWGZ@^t15JoiV1Fs1P&iaC=TGI`p1L0xLf@sh4s(Vv)npEh*CxS|Mtfl04*{ma0 zDxdT56j@bWFOHAzn`$${>D{+NM%}TMhG)-O)bcfAEoV>nM&=LN*t;o#s+Fn<-5*XXz1uGr{CSNRXnTxy zT`4o#UW&vzKL%tw#h{*ZVOc;9lz&VoQ<^SL^s@czW1-Ro^I63u*|Q_o zT_7lJbi9%GLoFLA+0vD#s}h%e6|sT+fk5XF8#$dvVZq+!d3qj^yNE+|Fqw@aaA5$r zespvwJD6)6GFDhsVn@@Od`A*U-D-}%o2`YfVWT@tVJFgj zdhWfY?-x8+n31a95a-!4qm{!&Lkz3BOskjIVjx~z|8vD%0ol3Q3`a#6$4wGPs?p2y`y+@ouI z`(k$~^*e5Zs&vbBt4>^ygWb{14pgGv$BQp0L68qhiF*O~T8FSI*-lx&yEgWDYS27h55%N{7>iM97OM-sHBXUQLD^7+o)GFjjYnvRcE{}k|WFg0epD{r5?lUU>TP}XIo0j0H~XbP+itm%tSBRxXH~SH6?6@U6E;|t zYBf^#tYbj>_H$_7+YtF$7%POGK7I1s22xY5|$i5S0@e6n*_o~d-ru~^Pc5w8r9g>zVk=&S@dIE8Zo!twFgUQ zM+s1q!L3#o1EXuna8f;YKH+cC#sZBr3NK&2G|gRkrOjuZm3^V(Ge+)pR%V(YrkCQq z3$AT?oACjDt1rRETm}mE$ku!sC!9u9Vx&`dW@y!7-WzXjeq8`w`-e}SG z3yV%Ylq{u`9=(ePT*Wh~b!!#5BVaQI@9FSIkQHb_T()M^ft%4H@fTBK0LYP0!hx8y zEX{lNrMUKZqk497OTcRQYk%5R?C~xIaAnUk1h@cU`_341j4@U6`(+>A z(k?hybU!-K1AjY*Uhc5M`Bcyh4%}3!aY}&0wOQ(OW~Y_JWPY@4+2UINwTGWjcf7Q? z8145;$Ble>2qp5cc6Z~=jp^iK5rQsH`eRd7%*658HqB6`G6#8u{zI%rC^Ak)T}sCZ zLVB&ze2swusgE)Z=HgOn;%`lQhS`-pF!h0)86hth4baTGSqjN3JOc?ZN(UT z@@@*O0cq{?G~*-MTs6+AFML{3oJA$nu2R}E;pAp-PvsBc&`@5aGAQ0+AvNqtD!Nns*lEm6Y+?Ur)pS)Uis$O z(e4YLt&H|q?p1Zi?V)e06qS;}-mLaZjY>kI6_jmx)3>&Yo0s~McJZu)vCl~q{Rnt! z71i&|jap&_F7Jq`mpfPyeJBX&(VAy0K~9GO!vVoD8O1Tbpk}G1<(PEu#n{x>C2n=X z3x*bJ{={sw6+1?$VRUwQ&NUz!o$PA^iWXPTn~H+stuRmApCXT|o8v<3?PBe! z;lP^itg7|q+p5_*Z=U)1NUl$9N3GaJ9Mrr%%h4I2a7$zJJ7{B@@DFPI^e9s^ENm$^ zd$_(s|4HlSmU>+-c5sT4hQ|DDU%GOG&7N1|^Q)uMI-r~5)Iqc*Ja=p=)^SHAct^0j z;~-a#u1q;t$RZG8Xlk6-?!v`S(s^;-+Wg23kIl@6x4&gB3Qh7vtI1T&K#rOEDzVq( zOFYiJ1^m!2^FpXDRQD|(AEnyhJ1%yMfgRy@ljimxv+9os(rdiAn?PCq85_;p2L=Ekc?zsv_6U-sv|xK3PL)c_@DOQ>){; z;g`J^UqW!v0?w7Do~4MpDG@2dRv9*tJj+}&}Mg+3@}ZO6C6a%onqNG%MvYpI^E83tRwNj2!|K5pI3R@M1vKeW?Q zUR*1hg}S+3)Ts9bKIdj}e^~$O)r&D^{rQrCp)Xf)(3TY(pWSX>tIRR!xWDIdi5x_H zyVVyCM!ofBPAFbtj3V8seqB5zCz;LTemIiyaV^=Q#dV>#1#z)l&$!1UQ&Zd5p3>Fg zy;{Men@Tq>mkh>~*T+*iL~!)Uqn=xBsjmp(lS#m52yAY2frgw2h8`D^c+IXTHWq5UWK zd}tTjQ#H{F&JS`T`^U%#Jop}Bm|jPFmak3ZOS_eP%I&5F)imHWPz6YMfMhYE{tNwD zx4LEIoPkh>78r+g5E}EQvlTSuQ+IX>&9@dX$fDh^x7^M!eix;a_aKZRs7`4zG($`C zlu9PUxB>bHB1cR)YuaRqHR<=$=nmzT(~sL3`z?3mQCP<<X0o#J8{vgE(|{Xis#n2lU*uGD}4n z*|u-{k|gzHB-CWEqzlpu)w;rlMSRYpqImcZyW2Ld3AJ(e^&pRPWfO02m1NEkkzEL)SW_2-0W4HR-(okIPQH?(_V(#cuoI^s{ zfqSxDje7BuOwG)jAWyv2A0MyNA-2ut?EY=AWPQu4sC1zl7$hdCow71g;hFj7cHp^( zwy;-TIC{KXwme)b0!sg=v$lycX1zFD$9qeYWYZMBES^`BUuK^1dA}KM*W59w&kJD7 zlGk?LP|+BP{PIlD_d zs2ed)Z@j&b){b-fhQi%**cSs(o}LPxR5DQ;*IqugN#c?heo5tf>SR5ik%RpaIw1F| zIoBR}9KWQUW#nGTtG3vi?Z?BfQ3<5h@0D3_<}ZlzExDx&SJK{>97W_T=W$~>@>a`EO?xI zTlg%L>?yol^J@LH={k7|$#V&ojRmtl_>31b*U81ZKb}DI9{E)6^e9aB+h~oIAdSQx zvGOOFf2HkpIoK359LbAD$M7Iu#$>H&MR|uA)GOI#_Q&5LUq5D?a3HYHANS?uMGnd^ z72cLq+)pIu_@d0RXCp-VSEHMGGLUk7QI&!P(q(Qd?I}o`OjYDGN{i$_!u`{y+j#fD z4giMLrvuwIT^1dUbpoiSiJ%G9d%Xc%$3JruIJnOWgn)LWxT zu5sDV*z|JGH1%mt&EvW~llIGp!?NSbd4|VH?Me%krc$;p-n!KPr2FxO$_^*C4HWrE z-_wWwi-F?l^?iBM*IeY!Bb-L6l%4#Za>4B1siQ9;3)0t9G**UM0W0NM+FH;Nn@c`2 z=dDS?6?Zz3XqKJUQqo+MRyEJ-)H9J~Xwg&vwuwcJC!2#(LL_C06oy&tCFXi|5{~Nn zmx@G>q};Sm5m^ie>2K47Pt++$cr%LXA89XMufXHaBj43xUDmo5d3qvnSFfgig1Iu_ z+b17%n=8*Ce-z)VFV}m|Xe$&tZ_Bdkd{DRJlgB}8mQ~V%Z=(H{R6|j|aa-dcekb<> zkH5J9y9pN<)h03zy$LuqFSnLmG-}>wZ;Xj*BY%SMY-(-gX-^cloMvJ#K6@(NXj<8A zqwRj+lG?Jv!4!IVfgHW-aZmfSll{yIO21r6rF`X#-C{iBWj|bUK^MQ00h=VG^TA$~ ziI|z4-64f?HjmX9-4y>BJEnI?&N38L7o82tu*Ud71>0t4nn+vDD*r!@h0m#b;B;&J z_S>66Fc7fyYIJ+-*#sTxK$>B`>;9^-qG>_lj-P{Cdy330Fe^Swgg{XWwfl{gE1KNc zXJ^P{hr`cN+(DSgd)~S>;Mf#N0}Y@OFR`&h^3j83_Hh+&`dTz@wV{)2-5ykgvFb}? zm+xDX60_*OKSRp-QOhfm-!U2jP=`wjg?asoY_?(-v~&YtP#Sf>a5(Jjg&C=UKdajG zv@^aWNHDK_>$9cn#Y_l@4b-aryaj0F1XY`e)dW|BP0XUMiQb>>UA>4w9Jwt7?XHB< zBdap>3+$KOW?SE&7e9?wA8%YUUu>FiQYLPd&Lpbl4rNvVbMNG0M%XXs)sAwnHlP&bxbEr**MO-jC&I5IA` zCpW~DTu%ghy$A2q3JMS6&sTQ6mG2r9?W2>H?0f4eLq1!A=-V&zEPIRM;jB&>w(X0r zMy`D#;9Kf{9=6$*%c{24RbXI=I&A6fd@PRmISl`KW`sXt&WzjPj2ou{eqJD=~A zmm}-ZUTh^oghX9H|rL8vXNXd{+>$6z}3-Q zel8_FSauS+J{P`gidhwa8P^TJeb+;|!Fw;5wrTP8XMX{ex{&S)wzc(xZ6S89^Zs_= zGvuZsWHi4EY+&RTa4k2tcKuZ3+Hc+`K3!ZB&U{7Oaprbh8o*YDp~ zgSV~##q%-haWdP!4SCG&XCk=;W_EBLk zDOM!|(3KjD;`GG-^0-dFGVHu82`-xp`m4~y7p-5}l*#o*JJG#?&ouUhWjcjvg2bBF zt$T9g_%pXzGGDsxj9|qPw_EOHLQL+l{3b=NiAjB#eOs=V4}&KzFE2E=gnVdvRGdAL zsiAu6VV1>`jcA&D{szImSj zL08=R9_=ifDDJ|2v8C%M_Ry>4XZJN@A$!uQ)P0-|_i^YoOFfaQF>?2W zo^h*vXU)!}mbWD)f1H*`Z<{F-qe$(7jLBo&FHD$=H_Ij#j3yJ<9bs%Npwe>@eW=o-EpqP(xhP;3{=~1>h9UE6ptm2d zPf}P)SG>Hqk=P~cIj7yJhu}~zV(VCOTA`|Wad39fXP7*aR)(ZbH8WaMWqPBN>tHv+ zZFY;}MpsZV$QlB7p0s{^=8!xj=nt=WxqLmAo^QRXRcX42+gjg$R>ZU{YX*+8PkuS9 z7}2hsj`OLvtU7SlHH&3XND7E?R#g8Ey`%_Z#TakRGt|aDaFLgI2?)uHy>p+RI%v7q zFyOM@bZR=G4F`?F;pmLvTE5lBCj=_&F%50)(|q=BbdKv&B@K6`Z#d2-Ujq9tLyUoM zlFJU=M13e9HIJrOQ(dqSTcXej-lCn4r(611g;1B2p>pt02`AA0+P!%B`00PJ100?U z>sP0s?A~jXcvsxnu0A0(K#0ynij<<*J8z2Q88#KH8_i8G0=2yN0f^uo4KElm&&S_M zqP|YfF(+U$T(0^|5Uv*2oAH>I?A;x1?aJ~kqm138uDE+)$c3ND_CR={kyRMrO9v;Wqv$TCHEJkmL z&PU{m3T4f+fNy)(;yMYO4=#=3m4hj^qqz3U11VOUnHYuKZ|e7|4IeyU>&rKJMf{vZ zKXcYEOeI6Bkn7oeZOd|1l_JY4osLDt8qbqd=cFKQJi^N5g-|&vi3KCYoWz0paAwPf zS93GcuE_V6YUD_B-raZp^W_&vp3F(e;@{+$>6~P*wZRU|q~_r$w_!-Unw**HKifj$ zU>ct$BO>EE$a24P*NtBz2_GXhRJ>F=$6ml(~bnohFXM-At+ZcU-HBG-7c zijfghBGq2a!t$=$3w?+w>L!aGTdrQ41&J2TaHg!N9hS?y+lyB!fXdD>x$-S>%W9}) zw!>%9UK|;c+BTx;B~x)rS*n#gDs~!B;c+9f$xCg{0gEj$Vxd)4+=EY!LLYwM^Vw=h^TR7zNQrZF3y4 zVDEdSSwd2+IivQ4zC833Bx+-6Xe1K|JQPISnNJ|zE>8CusrOoEtEJlwl^PVfn13%c z=`duAsbAmv=0kDQY$|sFA>>6s%Gs{+q#d2Gy)VT(uc)s-bkB%baH^wG_`T0eqQ{22}`zlt;r( z^R}cG>0e%x9z_HO+ETm94@zZ&4uwv&)TX4uf(?p9h2(m@t=%s$UY>-3cR|gfY&MTU zJv%Z(@9831CD^q4{fi32Z^aZJ$k39@Bdp@jp3-5e-uAwDW=!~Dz`;FpMQ4i7*zC9{ zK1l&thPN^a!t_xZv@7aUYcm;PcpCNOiN%Us<=CJ7nkY zN;znqw(T@LIy`97d})8bxwr$G9-B4lPy;E=D*sGZ`3#39vg zypnFY0453M!>xM*=5|Yi9XlRU_D_JX!KZC4JamQ-EQNv}zO&oj z4?@j}WhNUlYkaSBL%A&Eq%PQc)`wCCioTk<_qM&z+=x_7tP}UF%Roq_YoDNUxdZX^ zv~Eo4tcutZf|Xno$6peBSnlk3quSq$%8rQ?lYBG4)E}_I=d>lZpWf>18EO%tJjwR5Go~{4 z%zu`VPp41L_(It=VlUg5P^}ZoUt+$}3tfh~cXt~cPk`+?tBrh#@07F*7Vm`<*F}86 z4)>3;&a7CtQ4hb(qQ-U?jPQvq#f-YkPK(@9mWjCChr&GokyVpSA$?<0#WBMq1NG@O z-k0*Xs9;ackhC1KZg4PKeyK{RRY`B|D(`kuArSut=yhz^Q&E|n==1{ij4(&nsmS<~ za-Jyeu1yW8;yGI)Fh%c#4ON4gsWjH4>~E=E_lD^UNaf4Ibrg#dsU>YQTkuIMLr2`J z5SCB6SxdZ5Y!{tf^6TwfG)}%IZBC1pL}3hyZ^H|Q$R(DmU#BZBS{im~^8%IYxbw>BopsvX0|z|LO<76&4(~H~ zs3#UL;hk0F=xOl*p-cbdl6~mFW*2rn zI*?bWaJs1OwAK3NlOg-eJmY!Evu-R>zF^pKE*|YZG0Y$ zs7+@|;_Q%nruMGG_ZkgxmD0TZ3dEX+$rT!&Eg&#HTKh7N%Xsr4X=PeF} zI{D0k6ZitlJb69|3d+fzFy9RM#Pmp`jXH_4_muUA(9<~Er-zNFJfIeE%sYZe0~wvc%tlGN|i~YPX(D_h&dixO|9Nk!Tx)Esek6wlMd*o^ZSvR zu05vrwcRT|3~IPm6_KAm!06cd@4}udYT4s4n0GcNChXM&!nXbg9fSzpyZ48@_&f|; zaH2ECBY+g8m^m4I1qW?K{aIz~uJCkyXJ8It!QsIO9vi_-_G7Ok%`z3M9QDF~3>Th0 z?Kug8)<+OKdm2UH0w*1mB}s)h4+msSg2|ghtr^M-g((?h!NgkkGkr=D<6@#li%vK|Z>?`IRgLdHbAgY6{)&Eg7W zTZ)E%YTJ3v`peq;mcvS}<|aI+b()~`EGz<-Xmw=q_r47}q)bvnGX_*iCv$GE{^U~ME; zcE2N~rS|(Ob)qH;=O3x=Uw^a*J^qlqE-?ndkixzOV8Ljoe8>_u8udW&xNMIOTY_~V z3jQnHLHI=M62h<{Oa`b6Y@RaAj+)Px!Brh!e|xDyeoJe55>`fCL+U%t@}vy>@nJY5 zfYgUB_TnyvBr}*OT;+B!0d8=iARFWnM_}Zvz(Kh@UE8oi&B^h(GoalzKLt0spNyK5 zIttyv(Q5;7l1fqB)D##KIcX!G{CgWAM@geOU+b(>v>mQz_S>+z$NpBNq>GCK0P?kU8?kZe@M|b&Z4Oj-s8w; zn`B&SGrO=2-;1wGyTYl2aHBvGw#3L2dGb#AcmIcY?j8_?RavNcCiELAB(`H&3`A%Ip&x6Di5Y14WjW(^H-BN+10L z`2PJC!>7c>+!D%j-+?&_tox(FWNmV!(cDZeEF4&E5*EezmzSc~+I<&7Tn@#->tG*pSDheKYLO zH(6Z%AK!0~5LOO~zxYwWG8455uLB7NCTq-cU^i5@EJ&)KA`$qpfqj&?)7#aI+^?Fu?IEPq~CG5|p z`W`sN5m6sT7ta2mrh7brPq*b4j$NH%6n(RA0Gc9xMluOp%LY0y*+VEA{q!3qpib_f9<5AK%X)&4(L=S{Hu) z-Sy0;eD1F}Ms4spNn!J5b#?XmbLXhuym_-V-H|FMh2}KB4j2Q>AO6C_!wZCxrvZqq z=ePf=&|ijf$~s|&_7A7z>GG*!BukgQEw}a07d)o@A*SlfH!qnUEno~wV-`AsDHd#- zSg(h}w`h;g3-%N@z`^?Ek(UIPGZ@TZ(FKb9v(kfjb55ck>l<^57H|^x_xFRg?jUV` zeh-I$574sHK!zP#USoXhS6%TWLR;938sKK3DLk0Sg%jXV4Nxj zi>*F+p}LV}ce7_proChTfj9oVf;u?RDU7(RzlH%zCu$@9*AEHrpB|j|l_8Jpd#}ny zY6<}Qpj`+ddfTlM?$Qv7<4-bD7mawJpMd)X1+X(?6cfPy-9D{YFbio3`CSqO8K&W8 zt??fDmLpm=A>#Us`(Km}G}TdLJV_8bf*4d;DTRp01b-d(TThs)rzYxxF`MI9LADR# zkkn{$u)!+O2QGPY4v%pw71WeL5WzUy2&i5lVszMEL`$6g(~=UZ$2cnQA6AEU&}0KCFrZr|K*3Ic@#ZJVpgA8O1K9eCoj{-p9QwI-V;nONhjp4lmNyuWL`cQ!T5qodq$8Zd;{dtUI(dvTcwsiI^ z@wA85Z+Y=&h=n-okS6?{5Dh0c6v}}Y&Gu>3j0O4`&CY!l&i2mFUR`1gf#@&xd?U%tX&@Psk_1<1+Y;BkLg^^>I&XA83A-^BIj@Z`hz?}HCVFLiI~Ccd>&!))6sND}|Vgz3rzwN`^ z<3EpDP!tr&M$z(~GA-N$8(>-Zf9F{b37oNOy`8V=q{5`Z5S124dt#)&eo&VRSh2_7 zJ7~bpG776c_CG}Szp$*Xo_h%9{>*Srg2ukQ8i)`6yIyMpV@fg0kaJSt=Jkwq?@!TN znCcRi6*(_obf`{$&RmuaNTJ!OWU(Y%u$0P4=F2H}j z{14PH*r7XhiQxt~{*1l<^{+hr`2mjoj}P!v90%PW32tA#ZD@Lhq|t?+|LbT6T#s0* zUA+JP#F;P5v?YS&e4aR@`00fMSlem(`)hkUw!wl2lcPo zeiVuIFiWc-@%FFebczUJH{UIzR*0a#cuOUpNxcve2zRo!H%D)AxlMqQ&`=j5yx?RL z`r*q;})2RiJtWZYEaHU34^w{3?TSE>zPlW^#R1$7WGH0FV;%$TP94zuX@>mkL^I^k6( zh3vG0jt7dLWW*ijiRfaz?qM#|iph^}bnrjEQTRz?`o7@`XDJUX9EATk^79lVJDC36 zg5jJhA8%*d#+a#Y5j0r?Iz^E3a@`J`tTa}@MT?|ryn4QRpR~)Jbl-XO=*0d}TiKCd z@nHr{uk?aFh5Z(63Hn!NxJUhDt`oBaG6S#Uu;k>1X6WE$z;YU;+8YDbYW1_O%cSCKNpCC^wi`D5NRS zL<+i=&WtqGQur_HNt_y>>yeZ`T=fHuJ=EjZM=8QDP(rId53%RqL1yx{y7to$8B?X>c<&*hs zaz7)8?)A}TUm1LE7@WdtM9e>-|KaJeEmx1`G69473ojN{uh`a#U#9KdXd`NQjQJ`r z7$0P55n;T`&XAK_TO6pmU~WHls~7Hfv_|Ph8S;ogKuHCvKx6kRC`vZww^1%TlUR_b zo;!YOy9)!T&69ghM+X;^z%!rKwA0yMKnTW5;2(D^*M9j@UFfaU5|Q~6Ag+1^Q%*F7 z8|`ltNs55(%HPoJ(uw`6&vli9+v%BA6^(D4i@jwiN3m2C`3TQE)A*laoo{-R@KC2 z&q!Fc*NKP+xyljad$7ZeMlN=2E61`*lOB*iq@ep^zb$MvsxkKksW~giI)znBtY5QR z4$Dq8q3HqP=d?7GZJ4Nws{@V)418@<$V5@b2aoBj7O zDLdj(4@IKhXT#xg#|f~v+j=J(lWOpN*Ok*dgZlD>jLynuxhi*9{X3`2ffus$ceY?gbx!1Q6MA)UbpH{ag%!@}e1_^r z^xxIb%6$*8PpDfOa+aamcJPyW3&c36Id$)|+2)-Et8wnM#c}_dTDBH;8vsrpp~(8o zAH1ceG3#-wmo61h9d>h$C*OQ)FL03|0%L*r1>5)Z3&(0o!533 zFx%CvW7rPe`Jk!Lo^mjvaa-uHSUde;)-9-~Lr+i?D^hf`w1Z2Zd60lJ=d>LNv2G~8 z>n=Qiy|=*#*a#RBTuWVKF%$$MQi&o9a)XT-Jk}?p1CT9SHG$nQ)wu&fzlxpaM)$yY z;_v;b@F3nZ=8L3VVS2fU!Oh#djE)VyGCkC7FS&V_Q`}O2{^;l;*7kV>1iOA|k2{=%7Q5{l!GLXjh~o!o+~J2)E!z5Gfw&FL zF=*+(25Lj%%xTH_3T<)Gb14V*(l-PVz42xBgS6G*XMKLtSqgie{(SwtUtKPqBh~N~ zM7qBl(=FB9q@Cz5_|bSfPLH*J1Zyj1=xJvo#0PA%oSK%Qqyf{8(~2w>uVS>3;87jC)-HsMz@B5^HB?oKG(JO2-nL5bT zv8-g|bgW@!qX!$bgIL$XK=lK|tN*@+knYKkS>kh&8{GiYJi}eoN4vAKzvA=o4NP9L zTYq^4R9 z@dZJBIMac}(j21^{nk3$5=f|+9%VoJ>KAD&jxOnobg3)3KsvQd)xLG<0E*#1>^Um0jxJWG#3n<5fJUnwzYYje zrByrkeasW_xQ_90B2EqdcQsxvt20nY4*1*&kPN<3$Tub=`YMxWphpeME~44jwGI*D ziV&7tXno%^gNB=H^0Hu{T7hX4RcnPpK8g?xco?SvS^q$;Sed;gr~Sc8#;fn_k8n>A zuuxOdK{zg$O!OB+lWd6~fb^jFu0gz;{YqC`7@+;qkstl8FdB)g+s(FDXM%K&O107@ z6fsc9(nw1yyZ^a)IgJKcAQQ>jgrac$_Iz5pb=Sl7y$o6wlK}Rd^{WkIcw2m{s^S>u zrGD>vJ&G?D1IN9j?Llh6_qH%GS6J~5j-x^xisB0)7=IDyEEe>3D~E{G6;5(?aoEmv z+6~Ld*=~JC%EkRief%OHf<2pHViTEeO*#P?w@@3(=&dtJ*fTiQhFDa2n9hwV?bOVE zD0sDmV&SayIdUeNg3{)L27AOMLqhy(MV3b@z!0W}oRUAOQIISbr**hH&%BqX*9pr* z&lV*ccO*$NMzR{@uIrl4cc#UZugkid^k%2cL`MSoED*N4dHj*>NjSC7uTU(32qT0;MgOlg-JqD`IZ_b zpPbR&7V~o+6oKFsMs3%EdzA-vp|1PjDHC>ha3V6d#5`Fk?fg~_D1Gw$-M9M0n{|-Q z(I$3BBxk_|^ih7&BB)i8t;TWX<=1|J*FOuxL9Y+3Z$z4$S3{dQI2t=!*fTRQd;ea( ze7O90ezoep0v@OGeIX&}bq1SR#D2b^59-+G`9L(e@s_QYALf(%YqiuEAU#bbBdP>f zwO;*--jE#d#)xu%wuScCm~c5A(7D1Q`f|eXnV~8k-s~-ddj3%j*WvQ4iHdEpdYJQb zCJL?h@7zGMyqqhKATfsFo~UV$TR(2B z`@U6|-ylMF`GZ!eO)NR#tnnxB*S8a?r~3og?UytR4;x9^Q(H*Kro-!)Fd*#gfPDb* z>(UQfCFTQRATr7t;h<~$;IUi}@xM_tDC=7COxL?OGCsS(<`bok>jZ}CG3N1UjEX6K zg@Zu1$dDFR?;)2B``z2mR!v9x>cjen^W(Q^j$0$gmeF-iO_Y z9nzvXvXH3AKQYoZj!Dw@+W1a_`wwn(V_D?wtgBll24v zFNP<4zUxx=ZhXmWX8D8RwIJ<-JVP19F9t8tupo?TS24jw$VsHwus7d*1o8*KWjQG5 zgD-f=Jnw$V4_3E@QTV?cyX7uPEa)JCGX_EWrn-kNxTh+VSR0rC8hlU>YkBE9zL<=h zm7J0y;_q7(|GgWnTxE{$SmOaas8g={+M)WQZ0j0@nsR--2rI6$c zZrUw*eD{}s+-(;XsvNH-FipM3t()g|umtUN5h3o2VP&(Pa23*cbN1yKa{~%Ufdz&yhy6)CSLPAvT{{>|Y$W|LX&-UON|F zJ!O_vK?{$d5Gi7s4IDKMu)zw4=DU4MpfsouAn{8Fr||G{8cv)zA@$%vK+HH>?$oX7 z6bg4h{*uAWx;yM=5&AUsB>Z|u@WA2|Dt4P~QU+8Y1RB}CZE~olHZG(%ET5=0EGNqQ zh1mUgc7OlJBZ=Y3Vm}9|4U=}|Acdh#wILLRNzh1ac_tNt*KRGiUFa|L<^;0tK>vLb z;Fth~DM2xIor0S3oR9rnsmjc4%j3mS|uN+*0?+Y3he zO+B76J|fkgILQy*+_iEW?xp$(Ij~$@Nz!3Uah1E@K!l)8&a2D$?e+itn@<+goRc?E zV>~gCXCznD-SeDm0E3HKjenJd*5uQBX9x{EZu`Zqvf`9b0d@&$CyL=i!<9@P`gRc@ zB?Z_V4Ukxq=3e*tA`G(vTtn`|pQBsmzbI>)fCW+@ytkL*p1EN|9r8E#EAOPMWSBOb z8>^o8a3}ZyBCM_-iS$$zydX!+;VX)Gp9zG2uWq&@b#V^`9bLnKWfdcIbz7lDI4~Rf zuXjS2dH3LOZ<*Cc~by9~3J~bb>ezhfvi=T8k+;@cDI0ku- zmYP%VkhgP(({@-U#{CzBDy)k+JUjKbvT7?`_ZIeE!=mvz_#Z_nox$qIp!2Q#i#tI# z_OACzU$C?LVNrMPGFFl0217J3ImC3Gw z^Y2rJ$p9Zt<7m08iUJKge4$pt{M&T(V3m8-nJc%2ru-_e?0KH(XRPsWEiKdAjYSD)`MO7T$jvYNDCpZ@XzAb7aANpNm*Va8<4m2vEC^NX}~ zp}GACZI{*OKpD+y<^kQ@;w=~^l<8I4LilJ$u$W;^pNf z+AumN(Oesq)to~d=%dxj2yqU!t-H3x-ugv6qsqkQ=jeU^;Eks%<=Cy)Ivo$2*=sN` zgTqtdSCG)4I){Dm^3_{@VPL2Cf>oSKP(o>EDSbI9D|)iHy{=U%s_yxb{~HOMk- zJWdFG46u*DCgRX`dAM${=^)H?p+~zV%F$ssWVvzxu^ZgMKP(PjCCHvtOb+xT$+${H z>vE$-pyzw$H0MR+?5IMA_ z`ycgtG4;wsuv|UFT+BF>Flgp&1FWI02cyPBnt^et_xcxq z$TwLSz)&^2tq&f@3om30k0!1=Y|pfP3NuZ;V9p@N^zIkd7ARa|?Oz8M4+dTgTc4(Z zPg)1Y_l@^@9Hnm*_cw+HF{u@Y-s-8}9F}LhIvzB zkjAK+&|F+zRJ$(^Wi~>;`pRhYbdX`T42>ScLSfv^Ro8m;LMO+*NWtcBx%y|1hVBsO zDu^c|zT&=xF&i>0q3cPuT%1l{j$TnrT(WW7$6TE|Z%aO`mbiTX#yvZ7#0Wu4`ASBC z8CL{VK@lX1Nv1E01NQx(25HPSpvUk^QBHiy=RpLB%aJ!)exQZCL&AJ$MDET5Z zr7|%sRT~Q8$eOM@$eL|QFqqF?EW$;Tc$a!d^vf+Cr78Nj%;CQ}QSLH}^)rRQMSmK8 zx_qnOOd(faa<(^TTvI$@c^rgS1|xa|#H^pG{b5Qq){&5?0a4yUkaTLRc3mv>$I}f$ zVGf$4IIErb-E3k$p>7P`?xLnM{#7Q|d0R_ScFT%r;yHQD6+%C=Y}FiHoW81~0Q${N zB}^*;bczf-;#Z$}dtIPE;OvwRy!QP2-d-J`fcctMjXB`)W}Y|VWtR`J>#&ev2?PRC z8EUVkdrKO^zQ%A_8b&O&#FRY{{H_xM(5VeysnT(I@s760j3?U zTvL23^++amKN8#whOnbrB#mdnw;T`7xoym_5Uq5xx5$8XC2!wf91k<2p_>O2IXSo8 zStG@@!XjdFClQs*{rXgGXR_aQmMj-r&*zb-K|!DhK(X$0e`jt!a1A)PWZjsA_E)?> z3E3DHy7^fwn|M) zDc2IV7Yq{uVe3@?D`MW8$hl79_7bEs5vzAa03iu)jmGE|da&LMhqW*g?^KxUKX_OU zj8pJ`cU3KSh(u~h3wW=N(?ynUjROoa^!Ti8Z#E$;ycnrl=!-*B73b2c@_qH=&3G(s z70a{!F2*_U-izGaUl1)RVvZkO3fnh-G>eelm?j&9CTz2ad11xb-xZOt?rF#X5wq0Y z;=TBc%6oI~vS{rtQx6FNOCeQkn!C&Kt4kW0_QuVhjD>R#v7lxUb@zhX0V(UocdRd#0y7i_)O z5xIkZqF{4jCk0xQ0b)d~KYJ z`FgW6OtX66gjkIWavB)Z4PHc4Zg&5rZmQzd>!fs>PEW}@9O+`ChuzQeU}3s`d2Aak$r$bSwkWtlV)T`l4YWVDdc|gfsJRR__`ne{tD4r zBOCrC@W*N2YMA!)5GDuHz78z4H528onSxr*3|x?SGMT2{y(`l+W{A&KpryU4_l&n^crT4K>Q%8y9aX<+w%&2`R-ojJ1_{%HXp>2W8RF#%Zw+U(Uz}hCRCV-IrJruNpbUFlkGui0MHt z^nTm2s+noC8W)p*NU)%%_Hrx6es^GmgX&>}e!(66az^}jiCnh#k_yRqavMT#x%Zx1>v~w$cRNd~ zf)?svJEFU82yqU<)z2N)E2EG3)~v_BhSDaHJ)Vl!Fz)I3Ykhkpt5-eY6bvNd^A6+f6oev`?-yL?QtVfZTHTt&IG)70WeIk3={F?a66`h7@i-AH#!Tl%E zXRfS-;oVsdacI?1+GnX3P-TUeGZCVmQOh=Fq7}r|yY2um2sdFp*0K z8zu}E7V#R>VWQGuwq{;d`RA&qD(<8J|Gl{^t^Uk7``=uEkzcHq&tg>R7`qsncCavJ z!|%dV=NR=O5Db7i8~xI1x^Xlh3=GH&*>E2Im}-_7MzV1Zt?bz1ak?JT{Dt|Y0Z*`+ zqAK(ceJw+)jw%hOyEfJv^rynhwY31V#>ngK?ul!ouCS;G?jgJ}6Gcd!k!$ZA0W0K1 zJFVI-o#F&zXlgKOECTqB?0t85W`zdmcw3rhk+0t}{W8P?N7Zf(csTMV^@1PbVQ z)}jrcnP>q#kc@xBHby@2EBdbu8Pc1)QMg&=19mwFm2L;6cvkCDuP(I!cwip$cnNec zp&+C|w}qmc$Rc@UKJ?Wzwkd8i^`^#}8c#L9M_@JZRh!>iY!f%TA5444?(^I;ykMAt zu~=`;DLeaEK{egz+vy`yJ1|uI9AAcLi6NKnxBFf$M@9SCKsroD0?)I_xu?5D5yCrb zTw3nXp4g)wt5H5o<0PEoEV%yx5}Gtk5lPB!zbUdQ=XD9E(j^ZUZd*SCN|Hm;i3^7~=?yJ@!o+DWNQ=)`5nQhC_e*b?<2^uhZ% z)=z)@u+^>G&RYmfVUc!wnwdnu6oXnsytFB3%vXCT9m*@jR?&HiR2M^DI^18E+p`zH z^~s<%pjx)fHfs@pbqvQ$aW&%w`PJRk8p?s7qRLK)m9q%s`#*h_oJ+v6@PQAac=q4$ z5qkC}?@MpsKw}RkNe1h~ciP&<%#@-3TMQvv;-{290nFg}j;TRmD3KP*(N0#8zo45k zEcw^H4A9rYe$Rf@msFQ%FS?zKaDnm7cYgPXuMo zSG20YX}Krv?%983gn#D-VXCV*8@dKyNJ?}2Hh5ve;-OF=+|_}4!<-91Ttt-(6QenX zcYEQ2KC@uyy34&9s9KARxS=mixcmkJIdKuGq1lfoAgKZuSn((pvlP5pA)iFh^c>9c z&Fa7`Cq@t18h^)nww)#tx(xy1**#PkqxyZAjYrP|;QRn0@}>E;!tKsC_takKumz6x zG5)Lk`K=IYKUZwG7=_OZY)1fD0u~VR#bSuA8ACoK**1Fg?!cOCjKCGVl_g#G(*7i^|Kb+c>*! z!VP`HQqI#c_DMiowa-YW7R8w4F{3x?ZBKGmtmU_v{C3~|m1*V96~kR`j1$t{S{k|q z?oI`o?SYX%R<=Vi{)?Y!Gri-B0uRr_W;>XLAWZsUHt}Udw)e+6+NV9Ifn4o$Q0>@u z3ke#23@eHJX!IB zZSSjyX>BnSi*P2*AgB;AroW3a%DV!<(M?zubx9^f?AAw4aYKdVah>4_*cL(yjM4zl z%iRq}sKA{Tdhy^?qk%9WaZ@?{oS`!&V_K5fNy0O3Ix(c1Gu*>9;_`p^`toon_c!j7 zq$nw+LY5MWqQcm>Bo$KGvXh;$W#5xFB~tbw`<|__WKXujkbUe)jBO~}U@Y(b=yXo! zdVlZx&$*nduE{*lce(G+{aMVp=(eguQ#`H%t7K8HzvCYLbdN8uLeTLrK0UEo4`1}3 zo6+DX9%~+~6eH5+qX%xx$k7YzG-%0BBZN^ndK44|f#WW2ZU$&3aXsn}H% z-`{=Y`0=x{va&9x(u#memcFw&pOI)8(6Q^H$tOd?pb|Wu7~6L@C_|AYcYdFxL6oXmyKB6+sf>MWN2AfoL1e7r7X|pG6z9m-&|6 zTyvB`3g|VFA_;nJ`#@3y&7W`efQC#>Js6Ypit+>6&I^WMLufLIS-{uw0 z;4g?L-c}f&90gR^#ZHd8{4h)y{mW)@0I7Cy;@h6Md??-pzu=d9~Ej6~6n0r{@x&{7`xyePw5DVINZ10PuYfUD3Klnk3G1=hF%5@cs9rEBGz z3x?lNw14Et*n>JmDnMxXK|@OLdwp|xSh0<8odTAwSz_Ch-V6WoE>|API8~3&RT-eh z40eOhJ#V%GOakC;G*n$Cv>X@KHZz+4-uitsI4yG3y5;&%c?rP5r0?C?zBQqVASzSF z6ukm@K-9b232-Nw;&g>Mnqzwwn&qGS&ddR_{qkGgTyu!~$VWRM5p0;^qL-HWY|fEA zmS;*%E4Cfs)ldTomT?5U-oo;q^}I!IJ7GL~PTRIfGnci!jFdHgN8^(szjG+q5a4ys zMsd$oiVqCzlDdJEeUe2_ueY^C2^fIz%;tLQCJzjP^NiAy4ijNH;Up4wnl4Q_&x6z4 zwMws5rPa4|$ufTH<0qT3F7rQ->Fd2aQC{DK>SU2>|L;|LK-CXu)z`seRGx5i256)J zHP-~ScZyy#@FWVUYME*%2}iLb!-YMLq2kvtsBECtdao@83^RIcf6B|R6akje2sS$gmLUpdPtqUYz-8?7YnASZ4KiJycuL`5xw|TC zkrTjuJQUl1O2qA{66n6A(y9l$vV0r+3KhqShxx?(ag!a~{X~naVs~rH+B3VJ!~Alm z(%`D)D?UAKaRLtL)tu%n$H7HdjO@3#O3>-QsY)7|n=>y?JC`Yn5)#CPpUaAo_O0e4 zw}@|~sHVB(??(ZoZ%Hv&?}A~P*jyzTAn2orKdyL~7233lJ*s(zKBDgPM`09_u)e-< z#`AceARbnnR{_EQPo?G$dA|g?C()!YuC}S2f}SuB&# zRMf5K=FLxQM{XBRjV4ZmoncjrsF-u@T@VL;2kTNucmc%i@?892@!b9L`RkBRv!#4! zW#c5|&4e^ZZH$rUdiv&oO#eE!Qkw@Ts|88Iyy}@oa<~`FnoomjXF4;UG-F8Wq1EGm z57_5FbH`y0hE}@_>lD2WcFya~ALTU*ojfVJayh=(acNvDIc+GybUauKv{S zWQ2r;v*^+(I{fN!oLv>m-7DzSSF-+Vy`ycZ!3Je6gYNneQ(&PG{wGZGL)~u}5{)5n z_bedguV6A6*-E>CQ-0ptOrExd+WM$~>E(EZb|^c#ErEbu1@~KItL7VL?Fm{~_Xlzj zOvx$|Ahav0b$q!CB1oN16|0tiA}v?&!9Q5=fd&egDZUh5c|W;wwM z5S;HWI!`&Nb}w&)8@7<% z>hnRjz#<|Un!BD8zl(L6 zq(KcxI#0c1WMMj<1$F57>|j}|cIIT1KvlGq2AE|5T~WZ)aW~#aYRy8vqbCQn`C(TF z(^R%ThIV)~t*%%5i$nbCS%-BiL&yKzOvAt{|9S5C0+CE6_p=Y&ay~t-WB7|OZ$}SU zk}AOyNl((NHUpquX;oYWkKHarXC?{R4K=s8GO9o4!OsAF z04nCd^PpRJ_?8OOl_hP|*jR~H?64hJsd{&-6tV9~x&SA)t-|Rk3uTtV)ukR@qK9_( zQc6VhlgT0DVD*bl`q=7JYeS~jh6@1Ge3qk=v@IqtwC=`Pd`>_GItLzmF?k#lWVrBJ zr5+~46#&8vwm#VP+_X6|V16{1O!VQtaoqI5;FW{z)<340WT3uo5smI}HK;g_xUBv@ z`i8iHNEAgl`-?miyZlQW{;~kMs5%?z8-m$@;! z^FvNh2i`oJ{{75*ro2L-0t^8b2N!63p5No14NZjcLU63GD#rRu9}INxuio|@IlCte z+-5q%jVc^Q+1e^6p5oe5b~anoYudcb;5c2iW>p02Y*ijGbMWn16$W_iTGue+y7B7QE~D;eIvOo%LGA_h6`19a`uy9F(e?XBd9gpt6xNlSO%$ zEj&e$@ELeI!gf;ipPTrLLr%y&0G-v*<~^NrHmi7`UnnAz!5Gm6aCeOokPZWE{}E$; zhO8;nkTVu)4KYdJc^w`s#dHn~f%D-}C}oGIrTmF9!OaX4tTN>UM;i}>rcsN%m!`7j zj=htA7p9E1t;AE3+k^6_g-C@aY&&qi=g^a@78dDImD2?*CB4Ax6OiocFY3emXV=kD zi206!RY;1ApVzX#t`iRO$4(Q(T8*C{!I|LmWVxENz$W*2q3=_qL;{U>D2QXCL2rb$ob{M8YNs40{XL&JG_$=NN1iid^xvvM({Jxu^Q9Fqn34;p!?7mu^`3 z`mRm3JZ)%+^=up{*-LB{bu^0r+mE{ulRde`CDUinjQt)<(Vx1r`#E8wjUT&=u=R4% z5-f>*Dljl^NWM2FK9aHg6B3kOXKChMVM2>tNwM;E`koSA3tajj$z=p+2kL^2+gq+Q z6}E7Qb&f8%9~3Ff=RUKZQ0mLVk|{fduw2Q1`^HF>c2xg~KCJ|T;-)ob>ayfbu*>=C zL|AZ0bP0{!u5SijBTtspIeF?mJy^;}WE@9==D%jZ3`@Xk>$oWzd~k3BMuIn?gR(vf zibW=__s1<1PFr>4IpFg`P|2Mkfgof(-&AE(RYnC-(LbNS3|r30^TY{nW%jgId8mP=1Mc<~YQ)cscq-8tVK4wNae*Tcen~VL|%@tk%!L-Mge;p|G=Z4*qa-)VF{Y(0- zo9ucT~R_xMgET%4awJA~c?umBY^!hfoJn4!`nKDQVF6Iq_6 zY2o}G=|TItZif99NNsO(*S$z}II!>iWoXk)hDb;AA*x5j;iH=D>Qw|BAL^GThM<8y z^Qq&WX4-#rQhv$XG(*B4G{Zlt;BCm^>R*1##C{C({^79WqW2#5f_j*s+!gKvvvOeB z$v3;o<}o^AYqdFG;)@I5bllm2{MtwpfN% z5B=7Zpgk=S{Bh>afkWE|e7HNs=w1IQwee zq>Xvt<{w4n?=yDK0QSRk{>szPGdRQOla@u=XF&gOIjCd-OA_d_ftj>iG?>#V23cJN z^Q^-H4E4Jh#hlXhz;3UHU0|K+D9DVq?-vF5_6 zk)fd=%k?zbnmCLc@At{b?LKu_4gO{rBwIDLOun7d0qu*KU1Evb&qVU>Z)1wkf3H#} zlmER9{{3lo@5Iw)(vT3HRWQ7A^tTAfQo+Nj|DEac=3ih9 z^Q0fZb-qE8HlGn*{Q+GC(yxl8Tod7HJlM4t`mjaMXNS+s;M5Tc4aF`R{M`SSFQfsq zRvXmS&XDLn5H#_e(=Gt3a-Wqq4=c&D;yM(zixX`w-n6KV_4V(7D!+o^5|V%KO@5yDV)HeWX8g18_c}#N&{RNQM2Y_tK%3uw5aEXXCkMi zv(FDmNs%9Kjhl;2Cw;L7_*KT30a?8N*IHEj3J4q2qz2-Iu<%EYHi+%U$mDy6QFMA& zp|vL2>2E;CrQlH!l>XO%9D-2uToY#d3Y&sHig+%+J?A@Z;o%TAu16vE?h0WDu>8!o z+fdG@EcLAVIkz7k=eJZk{uU&?S^f>@l(y7mbGA5+HJb7&TX52x^Pc^aCi2f!|M$y1 zkVe5I20naAoU9P&b+y?0Pma*&qM+MgJiK^SwTJ9^_8C&!Hz_nNg&f@h18-YOv|-l& zIfO&uR)KrPG(M_L3>j2fXsomEx;3oK~7>)vfsXk{Mk zfvm01UY`tjd^cAkR=*5ibK3t3?vg**QPk~p4L4e1%h-X$5&~po7(3XVnyBn${G$xp z54NZlp#*8Z<(gj%th?NR(XYbIj3B^c;0{u>U_CvzM%n~B zhh@nR0RE)_sc(5h78>%o3=WUcPMD`z6K1>JD}q@itq617B+ejA%B*FLei40jYDDb$ zQiNQ8%K0Ds==wb6r?n-6CIBf(;15dLbTDh4#4pxkuf!n(QU0TN2<__3SO}DS z292{K)GMOF&`EBp%mQgT#j-;KTzfSwhc`J1`w6XEjiH~`@RXk#lplh^|KqX5jR!MFEE8P6nTa@fQZ;E4z*Uurs-)|KY;N+l0EnoU_?w zj%Y4HrfRcG&$-t(oi69LltrCU{W$am^FyJL75P?khoAD`J6DUK?c;gD{G{SYYSKI~ zH+j}J;MBdHe^*}T%Cf#TKtQ0CVFCUSA7M&+z7p0@(PG7)Mdnvo3SiZQL0@a-xd_HF zjSqGuv>Ck@avM$4@cZlt z@bwUj8?GQLWN2Y4H{yN3ev#~E|Kk7VS#M8iI7rM)@HJ!-P96p1S z|HVJwK7QFzaAM@Q84o@@{N-M)w*F0i{f_OENkY*ON(q!2)W5<#t&I;Sbz$_942Le{ zTe9_TJ%L=9dR@gVglk#UGqSiA*%A_ULXN7<+KJQ-Z_SWu@45vQwUT|#5H!)^-wa5^ zKMz#5ryt<>!Le;Nn%$c&FH(@+Si~~!c&~ju^u4MrimMu2)`A2^2JFSZsVewP6@eGe zK}d-uG-IC70r24sF`r8at?l0TPkgJR!CBja2?)U))chNO6X&^UJw%#3gjV1{3dr@% zxWORX{zAc=WfcW+E75?}1v%U%MYG3F<-dw=Yz9||`(g9fx1=}o=ce%_=VO-xu9`M! z^tPWAKhdahxoAf1)I$pzEskV#Z$xcRWiejow6)fylbbz+d1-=hO>+!mOBA*ury)rJ z7egK(IZNgWq(v=MO7}Rg&YK<@AG@d?%mJWd`}}MfhiMyF{}0}&!WihxQ-&GU;dYKqAH6fZj$ZSN2QJk2^L@1J!}SOt|U zQ9{#u1?s7n2i7)N&v`P)S!oUOV;d(FyIr! zgp*L-SFJL|Jg<+|^NX?BwI#;(@-J~?d%p0e&g~{%R0O-xV@wxn*B3i7igKad%`;B; zqq{pWL!pMI>fx0k8SJH{b>=fYrkiA5fYeuZG_`8^84OXSzAlAUUCrjYS>MAn_465` zXW!x%mBUu%7^=7?Vq%xRsZ_ zL-S+uzNCpamiAPx{zijVbtZG5^~?9*Y)d{ad1Y=u(%vwF`fNn61L4}0-M_g2T-QTC z4eSWl^C1)8d!yl>7#k>&9!rVP?ju;_Y31lL64cU*QIgAkyBom*=1Pn}#p|~gZBLZ1 zk}I_?B?V=-9GCJc&`Na)_O3+Ho`Ry$I-3Kv6e;0eN-bz`e#eY1`Ms1v#QW@<3DNH8 z2fYUI6|n-bWlw?6qEj>5V=!lwDVN)O;cpt`uewcUOGDeP2>sssbuwxr`Usw4tvH!a zIZIvU*A!uHZ|z}3zNn3~M^agDZKe2i&VZYMa9r;O7YvvMk`8ql94l^}D{_+!V3 zWxDDcu|ox2FX1rMA5!DpU-<1-O&K9BcWxhwj%~=Amqq9f)Z-Xh)ZW9NxPh>Leq;TX zn5&QakPrEsXV7C>ollUJMVx;NWI6%A30jD@dP&%WO1rUf=Z#NkYW9(?`!{PkX_+m(`cMJgx@bysq3I*vOR#6boANHw=?JZZhPnA(C06<7ogvCc z9ZGd((mITyUMq%&iuMxf5vu1OJYQZ|mFjFCXPy8WaL_ zK0Boy*}9Ip3b*9U?E=WH@-zU_Q>RyIQQa)!8Wecd)1-cvp0o~hYvmgRm?jkVv^9Q# z@Fz<3M?lll)fYOB)IscD51-b|c?V|l*ahqCXECUA5?4;pmc8-J3DA00^w6>Q7VSd8 z{Oy`tD%z>~Gx*Nu6>C$|Tz`=pHFf}K)v`Ewl=&|!bx;e=eO8fX5hM(oge%4xk^<2k zsgJZ~mt5Gh6l14er2$bvfFWsPjs~@KOySGau{#NucEvJ0U6WKuPv6o@xFo7-iLcgh zw<;6BcghqyO*RmXq3e51&0m$D@P-O=5Tjul#JCVbOD?cu(f}q)eCcJh8t_rrLV)f3 zv@1(6)lijOU|4le+~?X>zQt%Qg2WaGr~7?|7}0R2w(<#ORgd4_QKO_j z=c98$=bee@LWL!Wzvy(V2X)j*ceH&D)Y zIIwQOJa|_5vu#)0dvH)uQTk=}xvnA;ajnbyC`&d3%5mNC;;;7;x%4T0zsLONM#x<- zci4||mTqt%iebF@nLh!@)jSlU*L*SG*k;!_g8s?JYfw$Sc~!b-U2CYi^F8Rr>v-_c zo>XLfU2ot!n$;DpT?ha+#gtD3nY3kCC1mu`!gE6$@=I-t+(7|B6^sUgKwtBs5{j9myN1^gUWCTM5F6u1X9Wi)~xd8}Fv&mnz-mWn}&116$i4n#P&6!T> z#43N7s#7&73EY4S?gNejVs}E#aD7O`4O)J1privj0o^uz`JH8XdF`n8O>xq>)Qh%T zClK=zoz;vT!%}-nKt_mJ5bL4M@0qnJqlPU84=OxWH z)=bT`x{HZJ;cJDnW4#sRX)eK7^N7SQnpz=i+b7mJfT|duLwD zE&&EM**aBb586}AnmKUo6|JHTVs1bBm#5Pq@5I_-Le5NUP?$(x^`EzR&K}fWW$1y( z3&s-O8J=R&)#H-+y9Qn_+FcrSRoznlg*F@Pu-lC(b?yKNd1h<#3E=#FUH}H z6nMH)DS~DqJjx7_Xx-mUS->+#8dixOv%goO+c0=bE9#t%MsJxbmX?Br2u&EadLYke zXR_^J8cZ*F@!~<3W+*1_ zKfV$qdBwj4ltqnzq(iHjreyDdf1FavRpFCsKXS=T`jhGM9X(ccjBzlozjdo+HXk_H zk#BWKFR=5fS&T~q{N-Po)lRa$^UIj^gn_a=fi))Rnev7_2M99F0=fj2*X15BzJ_@B zAwFEDY%Wy|ROf=m{U*LA+6+~FZ)MyZxmL!OQS|a6HFU3}=s8;8%l z>i;?6teLHC;y)gtZ)M2_0h4bsXwDrPYgS-DcZ15n?QlU@d=OZjTok8+!DpxFTu*MA zbJY0}RV?G$r8awkyIBTRA=H??O`dauIf8>_Bu{L?%s%ld4=KoSVi7C9yL`~b(jN!o z#HeS(BW6Rn%nhS10mJ^g=`bZ)Mx>*EP7}Ub`hf>qB=a0obj8?F_qE$3Cm+C^?(Y4> zJvkf+0lEw^+iSsZ<sBDOpkvn%UUyz+5rBXOm&>j&gf2*GLxHov-hFL@m_`-Z!E2DIX_Zp)w z?XKXmeO*4_iCj|0{Ki{E5CNZQ|cYki1%;;us4MpytzTP{<_@V5i_RK(DzcE zm)(w^*0b}hWXPw-!JyQO0K@?4AbRtFaJu>m4&l=VcU>VuVK7?2Jl**zUQlhIh^Rx( zmfjSx+}Q;ZF6OMaTwiBQ{U^jRvzRsLfBT-bO=v%&>1y`LT6+6vmU9ha>7Qu~i(UE( zq}g!cp$R9=N49zE<>!$@?-v5-x5DscxEM^Y?TWCG#v10UVm|z=OA)Pt5XgI7L&4Ike^`A{pa8g3(Zo2W$kwAzu7XYF=wOY`(Np-v zaEYF6g4-T9KXDR%-^vaF$V2`6-`qjDE)x$_0o0y*4`oZEpKm4+^BY*PZ2L>CU^MUw zruVv)TbrI`bKc;Y21eE{uTVDHWHm_xH@EjCy+4*w$6(qQ0@cptQZuDs1!wOE%9>dE zm|$}#lx7QE2(%xnGpf@OprMrpZh*y^iFLvZC1z7VbMY{8fq!TP8|Dr4$BBOpTV-zU zvB+~bSBw$KA1uy;L5bP(=V(3_7_r}t$nGLoJk97jR7&U)pBosWmy5u5`BLpaZc#Nm zTvgSXrP=y+YF_CrYjEaHN(^5brv=@YF2BXXV@h3Ovf{n_jsq?PUW1eBK7=~p1snhE z)+X~8kh`hACSN@D$8$+M@MS~Pz-?rg`6DxcK2iX2FM6fg54=PZu+6yWGINJqnAMPU zi3|Td<>+gfj}NI+>_;FRfSMol9sp1%*{Vze|jMuj^9fxIkO0Trvb0|*QcZe!hyN(gl zki^7Ook~~rmsh$qA}YT0h$eq7l@3R(C;OM*hl8-QSHH;7^{Ss-9A>ft{G@B>OCs+T z;M5A($Lj??G!(E%jozNU{tfB=GiXS^@3WHDMGJGme0C_g3aXQQZXWA#0UuZ3R|O+# z9IESmi~jX6(0|J3kVS;w6&yK~VVdC#&maF}u*|gy8qM!8NpM-!QRtx4wA^!sLaTZUbq0epLJdpu*pKrqiojPT(FxNz+ScHXi ze4x;Y-5yujVWxx-K+U`Ip77OJB6PlZdgK@c@dcxVTb_{b=nG+}r2Xf?C8Bo<2l=oU zEXE)FzaN*N?ZBN&mo6a$uG{f4I}q+YC?1u#Zp2t*u|wO-$eRrMm&TQ!qd<&00iGId zS6dwlpQOSPn)*wzt=>vo}8RYY01@c2 zpe#M56nTIH*)M+N1MuM7+4Shr)9BGuolX~z{jrUHA2fcEl;G`b91&ar0ofp}E#Fw~ zr)OoIrO$)Y=N2o_GHyeS_9#2~%Yw!GjBLQlAzMVJjYiBShc$TWJF=S}?Yw&c%!9)Y zgL_1!)Gt{83B2*$?QCa#j#Q_X$&0f6S`t27@obr1^PkPlls9*p#cuilnee(a^Nztk zd;!>(DZml9*e}WWjJEeUD3wiN3*QDJVFrlCXH<>^D*#EI!{xp{kHfcG`XfiU01Ddo z<>1A$$f<=z<_k+Nh`rP(W8ON4?R6-{Y5%QuZkdmuTe9w(d%!Mu47LQACY=zkdO|lB z215I_PTdZ~Z~oVDzk_mClf9ItDZM4j(|m2)l|k!gs}wln@i%gYZa4~Vb6=lI1H!$6 z4Vt`8iK)Es%NTPHjUN~qDM7}dQRdEuYhb7nYYZH|FbI;;SX(BZ&?_w;Z~vBEy!QF~ z=Z<7g5?^~#12bPRX>6yL(OLMIb(#dbf49!;0kG75a+0v;lpjnt0P;__VBp^77_z${ zps3^g;w|{LN5+43y*GA1p1q*uZP+Q5p*&0Xz0c+#TK@{uz5=Zsz>fWRXAf%i#2*j( z18G+}esM!|zL<5&2U9wiI$L#ZyRNi92S;(=X{jLa_@gt;+1An+?gBRYrYj`Em=OC? zTzWfzhy_MlpYx37n&2|J8~*7t2b?ehF=*~fvgzztqoa_6{5iD^QT)-mcD*I2d`G~a5h`Qfwc_YaUCrmgP#xh?8)u3bL7rkfl8feqkp6t)P3abUdFijv_>T(1I z>YE1-ADX;8YT$JPhMar>^qluZ!?Sf9tQQ&(t%T{K`sOD29iy*{Wq(l$@XvU~H>Z1Yo3O2@SJ2*l zPEqvjZzywe?{X7%Xz3{)wiWcLnYpm$G0~Y(0kT`nF+Gf+dvBm`adYI)41m<5<>Cp#er9&D7U$7=U#=MIvtYw4oM7mDC`LaF>ZDK5%Z$MwE6i^v`IB{SVd06) zH;P$mLIoWSg)f+v-hczkm$5tGj39kRcSZIPjs7c`!}K~HKIb9+30#GV_h1m|zSzc1 zTya7};O2|AmM;8a%sK7yyK;5#%QG%qxCc7XL)SI)PM89`0!P90`1EahR;g~$O2kF~ zgQ~xwjhKtj7mar&?$)^{X4rgV3Wjyw|Jd6xrvQnH>h%e@t+?sX@qw*tRX&nq8EKgc z(|wuh0-s-}rF-AV)wjFelT&QK`)4;tp#?AKrFjq87-VD-hfm-9uu1&ovGY{>gATw< zLztz7Vi`M1jGt6ZARUxnKVHhXtsGW$7WwiETU9?5WYvnWqq6VtvtUqjy6_?a722<^dj8l4C zhq!}6klt(RwvB3<4|*ri)x8I2wK6>;O5ZsO6^S{&0ZT*%o=}0V?2gMjo4~ZC_oWB` zgIqs!?P|Nk$6R-2mKYc3Gev_~`jrt*Fk zF*E@(&GZvxXREgKBi=}o>n7IP6yhQm<_bqF;ed$A6{o!q5uO`+V;+B=`pLjo**%LT&`U2ent8#W+02bzc4D$OV1iZneDGh@x$n>aw=TT8HY!R2TF?C%}I_6fj?+`+nAebJ}66Jq83^ zy9iz1+{Vi2{<2e)JUnPxr<(xAH`SkR$BeSux8LV@A zG=*mPbe4@kpN|F8Mn3wGAo++AT*RD9N^VQm<1azujq3g#>3uutLa|*R`hcxnQcfC* zKW6Y+;tzAP`&EGbtu-mFx=JsNYtRZiiy!`lIGOCQ+l6VCGXZt0{=w}BO*$3N;HCYU zV8L`Xh;>6hknrpn8U&c8swE)pr(J0F zn&$$p1qjl5N#$lB$!)%v`P$~#%4}Ik4STh^{Dx!9!2zlEQWZdr&b?C?S?c_PBR?@<FT?5&bCg9u`+ksFuQrg}rH(5M_TqU+;!` zO>L_bWU+;BX+WV|uAhfQ_N{b*5MV0(1sQnxQA;9{1y^S(> z@P*NC9fr)&HY?>pyM+)1o<5!y@KCT_KhkT6m4D7Pze$z@F1N2>SdvP=53zSaS|Co+ z1VD$2X3h4@+Sc)JtKTI>zf;Rluz5Lkr%{s(E{5`s&G(P#2^DmwSU8t_gHCQ`u$7Kw z+fDgbLCBs1)s_Rp=n9$PQ}{VVL4>!JmfNnB4*Ybr40-q%>Fg? zFjN1WrCYk+SopbV^rJUPlbaFXb8AVO>O4aK>Q+l!6+6fhio$}l)zg)0O1C!4ENeb_ zQlp%GKV1)d^KK-QZzL1I&Gr(e_Z7?9IuX@o==#Ks+!O0oY7G3Bm!F>QD=*4z0(t&ou{9_Md|U!p-o2( z8a*o#m}=Yca7KvwD{l;~uNq)D&85#*f2UTZj_%+SB@Z|j`%Bm`rB6yTX-tiFr1^UE z+|JY1!?^ZFCcd*0 zzlA~!&|3%o4faJwHAjFKsm1gn5hCp`ajP z$Df!%M|FZ$O<$z0fk#Hl#5=5jnbJkFTljKCS#aW-b#cWEkv9j83@@d^=%TY}W0v>RE3BzTzqmX3Nps8WF zD0=PHDVJd!5Lb5B-#>;J@!JPep}mokAgcBY4{4)Fc-j_YB&0lf+x_A(m+WkKO|%P;-G zZ8jp$;H7`QgABX2-&5ISTZ1-WdN{r|ppCe@RzC3nmtHw1G6FF;m$%yJL<*PYh7I7K z;ck^!P%7v-g?AEVIsR34hu-FSKuE{03=OcB)1+;CzUZ*S9L;V8(mWNKU6hOw*(Erf z+J*O(I%ic_PQfVjc8;znxQs2+IFkAn%?@QJ&jB(c2&pL=ypw~|g{B^syt$oUMu<^R4NJrS%EOHkJ-<^C{43J1=oa*YBBQj6s|SS@i!L$gpy@?au6*u^CSqS0j?Tq7TW;X<>0o|rgqCO8R{`@LJySZ znlETp=&*y=6RZqS=zl=0_9(+-lo&A7hq#;`N9{jMD=c{{KZBrG=~V*iX>G(vr)<6k za32;yN1z-Fs^VmRz4d<@_w5#5&5+O%TXg9*DFrTKLs{mtQj1^Y94Mag;hkbG^9sO3 zmIs8>ui?!j?o%^zrI%wh9*He~MCeeR;Bw)@zpdAInlpeTy~f zOcX=(U+B6>bHn^#P5lzalue+3p0R!hh0A#u3;=rS|gg8*?aS{|cv5aev{=V-2T@EmT zcG*FDc-Wl~d%Cs%H-wf8RiabO1Z=Bz&}*B^b1`7@xyEJKj(#ycx-iy67_CV5gwMF| zNjb}j?__=rM}SpCY!BzeQaz7e%d&nnRccPOF}1E{!|K8)V80Tci!8r4{vVH&{RRbM zViB0_`}jc5iovD!1n>V495}k1&N$t7Yp!<}3gi6T@JsE#m{1 z3hd*LQUY(-mNW>2&%&cQEr^wh-wKk=z-F$gc>?dmSv&gY^Zt!r?%?)6;5-^$qOU!Ul`5bbW;yWg7&D zhr9N=l4A2gbZN|y{XgCzs5B=e0Kox2HTK4SJAO?7nHqpYz;Zb~Fg=%WTK{Wpd)+hy zDn06^(^>f}J;a(7^n#5K{P)}b@8`Sj0^5M;)~-1fb_mO$XJX=klc~Jw&`&f1H9kk)7X*)U z09z;&(J;Zc;Yd;l4hLZZ7>0|dxc&Twq-Rm@-Mf%@b6q#uP{1dqgyw%?LZe1CNuqdCyci~TPCQI*yE+m5zl|fzZ$5)x+7ozt0d9^u2s4dXti#gsa+PCqb?;h zg4vV9_p|?b0e>HZKI}JPx?Z-=21&D6T887!MYIo05LUmR1|yGq+7q4LdrTTbuOZR_ zfcHv+u|L${0kLmVmNTO3T|)DzWsE)f3?zfVR?+;i&mYXce_s20J@!(=1&~}L9_$a4 zi=R7QqD(w`71#j(OxwNm0IEsNEvt3i0=Hb9nCbuZId01F0J^w{3OC#?=sT$Q%mw!O ztMf*ekX2XFT^z}$RF|r9V{hy||N9zf=n*epG;f)CjCI%!_jH6R_zm_&Qxu5N6YKJS zJ&O0TGNf6!(BTkwvU>wmv|dT>(X%AZc*g{W--38AJwrem+Tjh9EoZiSXCPUfAjNSI zeF(LiNU#6;4YAsBbYzwN9Xv|&vY@k)bDAFd}!TukI-@s>MqyK zn3Yxg35bKEj7K)O5)88b+2DIl0`AQojeb0JYX@!n_0ZENKu)(j;Ve>Oy`w=FbbU=r z)yIF?FWslxWAR?pc}fi!zAuT&BOf0TFBare3vsv@>}&!27^H*&n*#P$#DfOJ2!Y+m$Owkj^uY$t_ac3R1Ee(sW<{C@AyJ9E=D#p) zc5MK_GZYPg1^9Jn7hv$VaWjB;N0quZk-bxm`5-(`^A%xR0I-4qVf^pmAyTY~C&MQG z?S#8*tr@H^1`ow9cmJAaE(J_zuw+~CuOHV}sa`H=z_^SUxJMzJ~! z`c&~^U0fMO>2S8jZS$sZTp7#A6f6N5O2A2m-9-Ow>i_a%hfJ@1iJ#5VS>ZV>p0=Ykp-|s8BX2p&XVqPjlS=_wG%`p!=EP8G+ zYU|(WVBtnz*XTk1QcsdC5>E=2Y`2+E=n1c@(z+=p4opy#ve|&P{j$MakW9k8u|}}M z6RSjVS^005JrZP}13$gP4LgK4bKyApT_eUF0?A9v;#8LbV6VK8+T{J@dwWXLw%cU8 zVryB-7GxVmL=@u5n}o&3b{VE+cm zdp?q9s#6;*L>*pI4=Co9*bS53p?j}S4s9&4cg)Y&gRo?}sdxM4oHbzQt4ED`_-%ckVZIPzqY;R(QnfR;&dlLt5-Z-x5e)?1Pt* z_3HGklMy{%2sh%Sbim|>9c=WeCk!3Q%dzvFs7~J1M}5V zE>Co+xvl8)Et*qTUw#;H)02UPHCE*xPk>vZ2R^>?g7?2~#QwQVp;aM{e{~g%zqCIO z`x=DfFvZa{%>gixR9x8Y94DeT3PyVX*3duSs8&PQ4?W{J`1BgwX0G~d@HqlU7b%hY zmfeRku`f;F?w(9C#p5SW`t4P9V#S=BhfQtd{Tct+j{?QIb);P&le$Z)eu1MMsFY^% z0DN=v6w(7><^Nse#XyT##Ty4-p}A1_Y#~_sMwH~(k*jLz&p>y9Xn~@5Z~^nH1V>zK zt=!nx>Op$-yb{ZfBa>}Oxq7KZK#zhi%>eYC0=;L;D?bmlXY1HuortJwk>^7sw!FL< zrM!OVjkb@OlsQjx0>3;0OtQd5nk4A^UD`Cb%<)X0?`DY^E8E$Hac@poZLbju+HB-z zcgbNQ7!2~xRR~|NT=}MmXf~j|QGUFiXr84GL^$K)Lqf))ry#qgfP5eNwdP*7Cyz#% zp=vxY`-7?N8SWwVp~ezN-)K5!TbS<%ecvEGxr+E(CBR`RtcbTgT;X4)6!pZU_G!W^ zX3F$@nT;7gx z?r&4iXs1L`dhW*0Z*{oti)Zd5;KDa$nCc9r8sCdLO2CZIkOt2vbeq{va$n@&v*ZIKfHOS@7({AX)j)KCbh!qqG^is{vO> z#k|)7CFZZ1F2p?Jvhb>2Hea0hdC|E36wJV`Us5WzzKNJLjuFcAbYFSdkY+PVH&oTFP7%ak)M~ioufYGjRo+-1%T+Dzp*J3B+TJ z=++@Kwl_O&Cto!ZDAG%1;}`>lEa$G^0IfV?@&BxHE{s=Gp4GeHZOMhi40nAB#~L{moomA> zP1eglBZrPwT)^$3kzj|)x+o!sV?ZqlPtViVM3irOoU2ckKKQj?)NJWuav9Y6jd-F=Ecw5rwbq`ysRx z_i4ML9T;2N(iSGRL0Y^u(3oaAFT&Jz&y^kE8cTm0SpA7NF&Y|t+KZ1?<)ufx!A1FG zj&@=9x{6yimf}{H>=NHKTGVu>yDWS;UgL&JwsRX_5;$Otkc->BH65#1?*v%8+7s3b zJH~rLptkVXx7QP|cH7%9OS;ffUA69+5IC_igs!asQFknWn+M+@6naczMRIjAEjA=m zC28s=nuI?tFwOy_foSS;sA1=5WPWX*m_+SP2i7nMuD+&T%Sv8fP=@RTCDfh(JnV&^ zX|FGMUi#2=y8y=b#p>PSu0H0=BcCnHeoUsR+B{0-zz5=Up(KoEK7Ji+zzu+-b5i~~ zhM8YVh-|H1G?(3#)sxRagkjrr2NCrwDUMbt9R)~GwzG9{8?I!VB!>^lBoKc#WHs&O zm$3F%)|`9(#@^An#hY9yENoJ4vbLJ8ggIhMXV?8U8$Iw|YtigL_M0j!bk?`W{ton- zHMnoMut_T_XGrrMhw1TR4dFk(yCHqMX98saG=$cq&i#A$z6R=8@0OIqw})C?8DT&e zXgjR3i1oAs5|=)g%9|P0(fQ&QD7^Xu+Yl`~I~BaTnvc(-IS=>uJ^N_f;1dopExh2& zAE))vIb+q(Cr)BXZD((lL4-*&y7h2>iiLq!eo01jGg?kb;W@ZzX}xQnA@*uP#;R#c zuQrG=#`P5QP__e&YFo+A4=+yc-YhLA!r0}MYFdk+tH6se0EI>5?$GW8Ak>DR@d94L zXWez7+EdQ_W_+-9WR|)*lORMGeJOcst7ei;N`3wib8I6~4_|-lv5#Vt4GkncvOgX^u6=sgihrnagEcw6!1j~S} zd}4#8x(BohGw=EUfq8j7j8&N7*$ecpWzRX>!!(_m{?RZ3_ zi<@EoKTr@lL z=~l~}0%SF>Re=2xcHLOY(+kuD5q6y~U6yBBXMCIwVrC;U*glFc?|m^PAK#?Xow|(qAw5@SW3hLlr%0 zBDjFgT@P^aYxyR5tcUFx&{LaH;5pwrbauo79_Ao<9?02|8~oxJ(rc!9(r|>$63nSP zy?uv$eFHP_LwCc|e0nzrrr!-6#60$atdL?wJ=dwu7O$7DYR?+=cfC>ZSFYG0mnC1g zHqdsG3X=n;Bn(LmmNtNaHe1vWWSmP(LLMjjdZC^Fx;IvJyL)2)u?4`0`x*8F*!#A! zNo3op#@h(p;lm*cK%hea@{9_LX;%c@ePVen6eLJSIy7+y7J7}(A*Oz-O{9E2Y5>{U}k+!z!5qeDuCdz`iH(43ixh%0j#{Y>~JELpLTvS**XX4`m~1t3F8MM z*M+94N+VJLGgMF}jfYRda5%7le+&Zml)h><9w(J%7^2Pn>mhqEIx~5%V8kK& zQl%t56>;nCqeVPtl%qQn6~(7mUBK9+M#DlZny+8G(u)DBqNlF9v6!f5tKqMdJ<~ar zYFDXc^s!wN*B){R$D-VYd)!|$Q;F&80ms`WI_cvF2B$mnC5RZi<%6_brLJ>#QDb~O zh>gokFE;AKyO<_P)KW|Ox4Ncinrsk1@d`%Rlu80jO$?U3LD~6sy#8S>y0CCIKSS{oIOT_~iq4v4HuLt5 zyehZ3h#9)a-%I6f+J~#g(?i6rxWkNX(0beSl~>!dso4OdtI4@ULkayZqWhVgp0<5|QS5Rg?B{6lr}~0n zuZgoXI~4+t*+e*WN{%_jDe4v7@-GJ}9p0O_fTBPdGhUQv(C?8oo5`@2D-Dw!LgtL&6zSwo4F%H<4&xoWA{4! z%j$>OkHA0Tr&$MapNq6IakM$gQOVw+`tgwpkBT#`lA5iic^N$&f4O}9U}RR++%X>1 za_OD@h%VMwx6lH1?bu0>zMh7BcA*||yNK~FQ+rLwpCyfzIR-0-CoX-@ign~*Z;?EM zc;$-rK`(L?;Y8!u=;UTv%Z9$hd+yTAT#W4HCrNtFgr4d6KZIR%TvglFRV1Vo0}&8G zNdZAgX}BsXs7NC%NOyM}P%$V;0SN`9yBkCWN$C!yyYmp=+#p`>eZKGg!w>Yt-fPb_ z*Nid8sIMpe{y~4q#-Z|AY1)Kek3IWSF2aje1&Vz|wu9w@l9?vm*V0@ zUa2a4cUnFW&Md&72d9H+sewtMd&8FP--~AnRFB zf)Hvv@3i*Jm4!F~oT?7xo>QejB2Gyo+UTbj3&~^vZVZ*r%hoRSfEMW-G1Oaw9N%uv zntv}_LHaA|J}^o$bmwRut3&mrkqz)OOj*0p=ycM*OeWhrIhL+*&#I_$OfNLMo zq9esYO46>Zh@~w~f8$mo{zfc|sJKIcjHlO`A;*whEIl!<+@2EYBl( zbU7uQ1KVcp<5{eDwrrif0IredbZ(g*;*)}mjW*JeZ8qX)_DRc;8cywk?u*(9J-c@~ zH~6zU<~5`_%S530;V3b-{FxrWsXvmx?U7-lgn=oOAe&T+e}OhiR;F-M8qixqQ+~>z zFpVJtnLIZgQe+xMsqWziFkb`fCDA>u>nriD^f0IAyqY&~|Bcht#7-wG(Co92&;-dX zpDyt%50z(JaOME7?A0uJ)8pV+mj%KblwtYXyZ9$oE11M4QF$MP z3`l;Gg=|VLg|9W84x{Pba0#}6Dhxk0b%y2PR+fbHHT1$div%r z*+R`0S(w8YqAIjMQ7tuy0GH0~KoNkZJwK-PMa`V@Tu%qiY5s} zhoWYCJdf)Ch6PWX9w|A#xs3e4vEM7@65YT6hUz2lw2A7uudfuB!YEp()?U|6Pn$J8b_=42gkE&7yeMqF9LsRzBm;KKP@gb3Q-Ro!QdrsO!>q(%lUKzL&knpy=qZDd`bC1{T2xp6g>TiWsXQ!brgusFE0RVNIsjncqQ-aDE z74&lgphv|^*?~-9P?_#xKpiLmfab5L)8my3GLx0^ywmC(?n2=e6L_90c9w`1RGvX{ zGhoqYhV6FGhQa*U{)HA(K|T#dmAR)$7I!c)ZVkdfgY^|}b^pjqbM+}m^}B={N11eQ z+p=Q-;3Npt&iI(v5}<<4u5)ux6)Rgq+C;D#oLxzT+t>wHVIl;-_l4%vFEkla^I(SO zt-}`KDja}R=axPqh39>5 zH*m)=@*~U!5Yg1S#Lk1fC_)nvh>3ghMvo*+7=&L>J=2Q; zVRSGwx5WYA<4*3@MC~d}v)308L7vf1upd39cKzmGpc~=lh@LUufJ)q6tO{w$r3X}M z0ow*`i6y`#h#(l7I#5@;t`eq4kA67cL=TARy>A<*O!u2;TNCJYmgjGv2Ee+Hdo( zorQ-!Z*-WD4Cu<}<N2NNA0%6aYyGkpIwC17`9lm&(gN z!NJcYVdBW(!Ep7X1|6`ElRlM1^N6Yt<(ntF16bgvLh$YPlr;w(kSEGbzsztA6S!9{ z0BP{cjQ70PXwK4N?3uFxVsk%F591T@aw)k9sdcPr#m!;}K;N*xxJ^d=K8HA2PPXh# zGd+NZ0RI~8*$Qpuch?9GQzGq_@D~?;v-whlTGPSeFCVvCR6y!vt*2OJ-dw?ME((p* z6L2~@4Xq&M;-8S2|ELrLDKq}#-wN#7mjdfnLw~CqpUkMa0;y2Ths)63Q!Bb_1ZF_apcDpB5%0nLFfy}N2G~M= zw4o+a`+=!RUg?GPcN0|v4*kGB1|zM6xdRuegI9sr?knt*5-xBc=hHoHX`9+#c>FeC6#EQt9+ zq!U+@;0_Ebd|nr{SG&D7KMeMI2hMs#EAe$iirn|_{;>{g9do=)FuEK0 zAT&WcN{}(?opy%C=eoJPJfXNKaJTaS-`)K3_HTDvei`G0dp$BH0+gLdU7b@rmg~xQ z9hIUhf4I@#DF+sO4qf!Xf2Gc^DY$(*#bx@@;L`fU)EBWjsc%g9VnO- zGb^OuZckIA1GZCt2qVLU)1YAWrsB!_Xd0l`qIoxUy9vXX?7 zpD+&%quRN`Ew!BWPBqUs+;GLga?Z&{RTm1Vqu4KpR|TNX`hB#7Hic)7*`X6*I(lFc zT7Vnv0iZPn=)q~0MzBCipY2m*Pw6$6!17@5utoH3oW4PGOis#;$*!!V4d2r26i5B;>~~Ig-DL>Lb?QTz0T}Z_HofazB@=W= z@zIVciOrLZB@WzSgUfu<;awo*rEmclh`Or=?2|w|c{PiWYrxqdJ*Bf%U9tzL;SAq& zAqs4rTzR_`3%xeptX$$v`dB(m?~jKuw&aCtdfG-L%0^zTxJ3bEfle_s4+TUclLQqP zCgz*wP8k-CR6X;jB1%%vG9QVna}c?+)V~-Z%?!tn(uK5&(eQf%@-XUgF-ylq`$$!M zKYCe*_X7YS#j*lyZ&^@(JuFSTndfwzlq259Nv#bq|M_J4^X42Z+`o!1 zA}naxdf!(U>qB#L+Ex@xcFT`^o|^<-S;xkc9ecp;y%^Xf^ztUzI0jUS1HXNHfZo7| zu*L1x-U$-=`!NE=66WN1(C=1Knu)IH!=d!dsXYZWoUKnH(6e@z6ba`nyRH*nrML_g zAX#rXZ1yU^iQ$U1EfO7;*iqg?Rxe~zTD!_zlAxBNAsEAIw0el*5z|?yqcSPwrP{C* z#5XnxLo`kIL2NST8cx_IYL_X^($AmXry8nY8oNzXyo#UHK_Xd{&a(3&Xe?L@?f@rQ zx36Syj1{0FkfVMw_q_~LspZ$63iknjm7>*7p(mi}slSQNOtJOKr%8{#ej;*e{rtf; z%E03SJ#-Dma*rE$SE;eX#v0YqYvragTak%Az+!~)6)c5K&TLrQO~9kb{)=CuC5#a~ zu8DE}8&;T}xGLWLfo<+l++Ep?N9YL26h#ULix&~{N>D5{X)s+8ob*cQ&tGuSp7t7! z4UWj;_5!_(0U1+gLA zR{bRev&5+71T2S$YuTN__E#woVaiFU$zC;vAdao0AYU?paMq*sL3Jy#Gm^ zU9D6DdXGoK-+c^sFzhE4Oa)0bxhF95n5EKg-JV=veMufE`RnV3T{C-s+rfX*3>hzi zdn_Q}BIh!E6dVaux^I@YB%k{83Kh;p%reQtz**5-t+@L$bvgcTwmFMJzZHmP1A?Id zT=w^3;KAAVZ}4E2MhV$vTek0g{w{t$<9P*W2!+?zpAxDD0*`4g@}VzI%t(8VkSp3@ zu0>0m8mLILL&7dS>t6FqPrqoLb}wbC6$HhWT3t=itAy5e@g1aK&!s7;egkZMw82dvfncWOj$lsC!U(j;$VsfgF)qJrj~fmSZh+p13>wTr%wb$V%~QX?#0x| zs)DF}rJj(0=W%n4&s%z*vxYD{+9pFQNS{{LUm=*vEi=y6NoFXz)^DT33O#$H%5Mc0 zaXlXA+PujOBLo~8nEMp(3+~u@rfh+DUZ-b0TDMoG*I^kT7&Evzp+X;E$yIF{_Gprb z6d;~OaYlO5rDH-HP{&xfj$FZAg9B2}j3D5CX3c|VpgjfY7Crdkbn!3VFCh3k<6I9_tDyQUG+j?S^E%mDA535$zzhLdc?g>#5ZjM0PMSaBPrdeT0rY#BIW zZask`CRW(ctsdIiZy4u;>(K@lOM;5^%xg}4EH*RoG$t^=*hRkn#x8BrV89~Be!Kd0 zbb~s3;acf)isrF#^dt^tF*Rfs9J14Vb>}~A8-D)KkDDs{j?5ZH{2JxHO)V(4B{&#< z8Fgx<{1B<$LaF^iaIeN^D-LIe(xNg6suLFhg-_nwo_-3?8FgtdM-cnnmFZ%QfRyzJ zOkj4IvH(c%16!7#%BF0vOxuSG5iGd*Mm_f(JZDY1V!po8zSL@MGcyz47KrqQWE5C3 zE�D17ZXaxk;zYG+5CL-uI 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