From 22f6fab2f5b51a749a2742bc9229e4a3b6161701 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 24 May 2019 21:50:08 +0200 Subject: [PATCH 0001/1078] Modernize build (Require Java 8 & Jenkins 2.60.3) (#127) --- Jenkinsfile | 4 +- pom.xml | 67 +++++++++---------- .../BackwardCompatibility.java | 7 +- .../plugins/lockableresources/LockStep.java | 3 - .../lockableresources/LockStepExecution.java | 5 +- .../lockableresources/LockStepResource.java | 3 - .../lockableresources/LockableResource.java | 9 +-- .../LockableResourcesManager.java | 42 ++++++------ .../RequiredResourcesProperty.java | 2 +- .../actions/LockableResourcesRootAction.java | 8 +-- .../actions/LockedResourcesBuildAction.java | 2 +- .../queue/LockRunListener.java | 9 +-- .../LockableResourcesQueueTaskDispatcher.java | 4 +- .../queue/LockableResourcesStruct.java | 7 +- .../queue/QueuedContextStruct.java | 3 - .../BasicIntegrationTest.java | 1 - .../lockableresources/LockStepTest.java | 6 +- ...LockableResourceRootActionSEC1361Test.java | 8 +-- 18 files changed, 80 insertions(+), 110 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a229fa517..64ffb54d2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1 +1,3 @@ -buildPlugin() +#!groovy +buildPlugin(configurations: buildPlugin.recommendedConfigurations()) + diff --git a/pom.xml b/pom.xml index b477f183b..27fbdb91a 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.jenkins-ci.plugins plugin - 2.24 + 3.37 @@ -27,15 +27,12 @@ computers) that can be used by builds. If a build requires an external resource which is already locked, it will wait for the resource to be free. - https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin + https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin - - 1.14 - 1.609.1 - - false + 8 + 2.12 + 2.60.3 @@ -72,17 +69,12 @@ org.jenkins-ci.plugins mailer - 1.5 - - - org.jenkins-ci.plugins.workflow - workflow-step-api - ${workflow.version} + 1.13 org.jenkins-ci.plugins.workflow workflow-support - ${workflow.version} + ${workflow-support.version} org.jenkins-ci.plugins @@ -92,39 +84,45 @@ org.jenkins-ci.plugins script-security - 1.26 + 1.33 com.infradna.tool bridge-method-annotation 1.14 - true + provided + + + org.jenkins-ci + annotation-indexer + + org.jenkins-ci.plugins.workflow - workflow-aggregator - ${workflow.version} + workflow-support + ${workflow-support.version} + tests test org.jenkins-ci.plugins.workflow - workflow-support - ${workflow.version} - tests + workflow-basic-steps + 2.2 test - - org.jenkins-ci.modules - sshd - 1.6 + + org.jenkins-ci.plugins.workflow + workflow-cps + 2.10 test - - org.jenkins-ci.plugins - junit - 1.13 + + org.jenkins-ci.plugins.workflow + workflow-job + 2.0 test @@ -143,7 +141,6 @@ maven-release-plugin - 2.5.2 false @@ -154,14 +151,14 @@ 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/ @@ -169,7 +166,7 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - HEAD - + HEAD + diff --git a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java index 12b7af7c4..6f3f20e3e 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java @@ -18,9 +18,6 @@ import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; -import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct; -import org.jenkins.plugins.lockableresources.LockableResource; -import org.jenkins.plugins.lockableresources.LockableResourcesManager; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,9 +31,9 @@ public static void compatibilityMigration() { List resources = LockableResourcesManager.get().getResources(); for (LockableResource resource : resources) { List queuedContexts = resource.getQueuedContexts(); - if (queuedContexts.size() > 0) { + if (!queuedContexts.isEmpty()) { for (StepContext queuedContext : queuedContexts) { - List resourcesNames = new ArrayList(); + List resourcesNames = new ArrayList<>(); resourcesNames.add(resource.getName()); LockableResourcesStruct resourceHolder = new LockableResourcesStruct(resourcesNames, "", 0); LockableResourcesManager.get().queueContext(queuedContext, Arrays.asList(resourceHolder), resource.getName()); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 739a0b043..0944aa941 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -2,7 +2,6 @@ import java.io.Serializable; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; @@ -14,9 +13,7 @@ import hudson.Extension; import hudson.model.AutoCompletionCandidates; import hudson.util.FormValidation; -import hudson.Util; -import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.CheckForNull; public class LockStep extends AbstractStepImpl implements Serializable { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 87aa18558..9a100c873 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -52,7 +52,7 @@ public boolean start() throws Exception { List resourceHolderList = new ArrayList<>(); for (LockStepResource resource : step.getResources()) { - List resources = new ArrayList(); + List resources = new ArrayList<>(); if (resource.resource != null) { if (LockableResourcesManager.get().createResource(resource.resource)) { listener.getLogger().println("Resource [" + resource + "] did not exist. Created."); @@ -87,8 +87,7 @@ public static void proceed(final List resourcenames, StepContext context try { PauseAction.endCurrentPause(node); BodyInvoker bodyInvoker = context.newBodyInvoker(). - withCallback(new Callback(resourcenames, resourceDescription, variable, inversePrecedence)). - withDisplayName(null); + withCallback(new Callback(resourcenames, resourceDescription, variable, inversePrecedence)); if(variable != null && variable.length()>0) // set the variable for the duration of the block bodyInvoker.withContext(EnvironmentExpander.merge(context.get(EnvironmentExpander.class), new EnvironmentExpander() { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java index 6665a13fe..428f73a5c 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java @@ -2,8 +2,6 @@ import java.io.Serializable; -import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; -import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; @@ -15,7 +13,6 @@ import hudson.util.FormValidation; import hudson.Util; -import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.CheckForNull; public class LockStepResource extends AbstractDescribableImpl implements Serializable { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 47b1726c8..58f1816ab 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -9,9 +9,7 @@ package org.jenkins.plugins.lockableresources; import groovy.lang.Binding; -import groovy.lang.GroovyShell; import hudson.Extension; -import hudson.PluginManager; import hudson.Util; import hudson.model.AbstractDescribableImpl; import hudson.model.AbstractBuild; @@ -23,11 +21,9 @@ import hudson.model.User; import hudson.tasks.Mailer.UserProperty; -import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -37,7 +33,6 @@ import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.workflow.steps.StepContext; -import org.jinterop.winreg.IJIWinReg.saveFile; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.export.Exported; @@ -78,7 +73,7 @@ public class LockableResource extends AbstractDescribableImpl * could be locked at once. See queuedContexts in {@link LockableResourcesManager}. */ @Deprecated - private List queuedContexts = new ArrayList(); + private List queuedContexts = new ArrayList<>(); @Deprecated public LockableResource( @@ -96,7 +91,7 @@ public LockableResource(String name) { private Object readResolve() { if (queuedContexts == null) { // this field was added after the initial version if this class - queuedContexts = new ArrayList(); + queuedContexts = new ArrayList<>(); } return this; } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index dd28beff6..84f52364e 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -11,7 +11,6 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.Extension; import hudson.BulkChange; -import hudson.model.AbstractBuild; import hudson.model.Run; import java.io.IOException; @@ -22,7 +21,6 @@ import java.util.Set; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -59,10 +57,10 @@ public class LockableResourcesManager extends GlobalConfiguration { * Only used when this lockable resource is tried to be locked by {@link LockStep}, * otherwise (freestyle builds) regular Jenkins queue is used. */ - private List queuedContexts = new ArrayList(); + private List queuedContexts = new ArrayList<>(); public LockableResourcesManager() { - resources = new ArrayList(); + resources = new ArrayList<>(); load(); } @@ -71,7 +69,7 @@ public List getResources() { } public List getResourcesFromProject(String fullName) { - List matching = new ArrayList(); + List matching = new ArrayList<>(); for (LockableResource r : resources) { String rName = r.getQueueItemProject(); if (rName != null && rName.equals(fullName)) { @@ -82,7 +80,7 @@ public List getResourcesFromProject(String fullName) { } public List getResourcesFromBuild(Run build) { - List matching = new ArrayList(); + List matching = new ArrayList<>(); for (LockableResource r : resources) { Run rBuild = r.getBuild(); if (rBuild != null && rBuild == build) { @@ -99,7 +97,7 @@ public Boolean isValidLabel(String label) public Set getAllLabels() { - Set labels = new HashSet(); + Set labels = new HashSet<>(); for (LockableResource r : this.resources) { String rl = r.getLabels(); if (rl == null || "".equals(rl)) @@ -123,7 +121,7 @@ public int getFreeResourceAmount(String label) public List getResourcesWithLabel(String label, Map params) { - List found = new ArrayList(); + List found = new ArrayList<>(); for (LockableResource r : this.resources) { if (r.isValidLabel(label, params)) found.add(r); @@ -143,7 +141,7 @@ public List getResourcesWithLabel(String label, @Nonnull public List getResourcesMatchingScript(@Nonnull SecureGroovyScript script, @CheckForNull Map params) throws ExecutionException{ - List found = new ArrayList(); + List found = new ArrayList<>(); for (LockableResource r : this.resources) { if (r.scriptMatches(script, params)) found.add(r); @@ -206,7 +204,7 @@ public synchronized List queue(LockableResourcesStruct require public synchronized List tryQueue(LockableResourcesStruct requiredResources, long queueItemId, String queueItemProject, int number, Map params, Logger log) throws ExecutionException { - List selected = new ArrayList(); + List selected = new ArrayList<>(); if (!checkCurrentResourcesStatus(selected, queueItemProject, queueItemId, log)) { // The project has another buildable item waiting -> bail out @@ -217,7 +215,7 @@ public synchronized List tryQueue(LockableResourcesStruct requ } boolean candidatesByScript=false; - List candidates = new ArrayList(); + List candidates = new ArrayList<>(); final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); if (requiredResources.label != null && requiredResources.label.isEmpty() && systemGroovyScript == null) { candidates = requiredResources.required; @@ -237,7 +235,7 @@ public synchronized List tryQueue(LockableResourcesStruct requ // if did not get wanted amount or did not get all final int required_amount; - if (candidatesByScript && candidates.size() == 0) { + if (candidatesByScript && candidates.isEmpty()) { /** * If the groovy script does not return any candidates, it means nothing is needed, even * if a higher amount is specified. A valid use case is a Matrix job, when not all @@ -318,7 +316,7 @@ public synchronized boolean lock(Set resources, if (context != null) { // since LockableResource contains transient variables, they cannot be correctly serialized // hence we use their unique resource names - List resourceNames = new ArrayList(); + List resourceNames = new ArrayList<>(); for (LockableResource resource : resources) { resourceNames.add(resource.getName()); } @@ -349,7 +347,7 @@ public synchronized void unlock(List resourcesToUnLock, @Nulla public synchronized void unlock(@Nullable List resourcesToUnLock, @Nullable Run build, String requiredVar, boolean inversePrecedence) { - List resourceNamesToUnLock = new ArrayList(); + List resourceNamesToUnLock = new ArrayList<>(); if (resourcesToUnLock != null) { for (LockableResource r : resourcesToUnLock) { resourceNamesToUnLock.add(r.getName()); @@ -361,7 +359,7 @@ public synchronized void unlock(@Nullable List resourcesToUnLo public synchronized void unlockNames(@Nullable List resourceNamesToUnLock, @Nullable Run build, String requiredVar, boolean inversePrecedence) { // make sure there is a list of resource names to unlock - if (resourceNamesToUnLock == null || (resourceNamesToUnLock.size() == 0)) { + if (resourceNamesToUnLock == null || (resourceNamesToUnLock.isEmpty())) { return; } @@ -400,7 +398,7 @@ public synchronized void unlockNames(@Nullable List resourceNamesToUnLoc // remove context from queue and process it unqueueContext(nextContext.getContext()); - List resourceNamesToLock = new ArrayList(); + List resourceNamesToLock = new ArrayList<>(); // lock all (old and new resources) for (LockableResource requiredResource : requiredResourceForNextContext) { @@ -419,7 +417,7 @@ public synchronized void unlockNames(@Nullable List resourceNamesToUnLoc } // determine old resources no longer needed - List freeResources = new ArrayList(); + List freeResources = new ArrayList<>(); for (String resourceNameToUnlock : remainingResourceNamesToUnLock) { boolean resourceStillNeeded = false; for (LockableResource requiredResource : requiredResourceForNextContext) { @@ -454,7 +452,6 @@ public synchronized void unlockNames(@Nullable List resourceNamesToUnLoc @CheckForNull private QueuedContextStruct getNextQueuedContext(List resourceNamesToUnLock, boolean inversePrecedence, QueuedContextStruct from) { QueuedContextStruct newestEntry = null; - List requiredResourceForNextContext = null; int fromIndex = from != null ? this.queuedContexts.indexOf(from) + 1 : 0; if (!inversePrecedence) { for (int i = fromIndex; i < this.queuedContexts.size(); i++) { @@ -465,7 +462,7 @@ private QueuedContextStruct getNextQueuedContext(List resourceNamesToUnL } } else { long newest = 0; - List orphan = new ArrayList(); + List orphan = new ArrayList<>(); for (int i = fromIndex; i < this.queuedContexts.size(); i++) { QueuedContextStruct entry = this.queuedContexts.get(i); if (checkResourcesAvailability(entry.getResources(), null, resourceNamesToUnLock) != null) { @@ -538,7 +535,7 @@ private void unreserveResources(@Nonnull List resources) { } public synchronized void unreserve(List resources) { // make sure there is a list of resources to unreserve - if (resources == null || (resources.size() == 0)) { + if (resources == null || (resources.isEmpty())) { return; } List resourceNamesToUnreserve = new ArrayList<>(); @@ -591,7 +588,7 @@ public synchronized void unreserve(List resources) { return; } else { unreserveResources(resources); - List resourceNamesToLock = new ArrayList(); + List resourceNamesToLock = new ArrayList<>(); // lock all (old and new resources) for (LockableResource requiredResource : requiredResourceForNextContext) { @@ -687,7 +684,7 @@ public synchronized Set checkResourcesAvailability(List selected = new ArrayList(); + List selected = new ArrayList<>(); // some resources might be already locked, but will be freed. // Determine if these resources can be reused @@ -786,6 +783,7 @@ public static LockableResourcesManager get() { .getDescriptorOrDie(LockableResourcesManager.class); } + @Override public synchronized void save() { if(BulkChange.contains(this)) return; diff --git a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java index 2da486021..93f65dd32 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java @@ -159,7 +159,7 @@ public FormValidation doCheckResourceNames(@QueryParameter String value, return FormValidation.error( "Only label, groovy expression, or resources can be defined, not more than one."); } else { - List wrongNames = new ArrayList(); + List wrongNames = new ArrayList<>(); for (String name : names.split("\\s+")) { boolean found = false; for (LockableResource r : LockableResourcesManager.get() diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 08770d5ae..aaa20661b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -99,7 +99,7 @@ public void doUnlock(StaplerRequest req, StaplerResponse rsp) return; } - List resources = new ArrayList(); + List resources = new ArrayList<>(); resources.add(r); LockableResourcesManager.get().unlock(resources, null); @@ -117,7 +117,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) return; } - List resources = new ArrayList(); + List resources = new ArrayList<>(); resources.add(r); String userName = getUserName(); if (userName != null) @@ -143,7 +143,7 @@ public void doUnreserve(StaplerRequest req, StaplerResponse rsp) throw new AccessDeniedException2(Jenkins.getAuthentication(), RESERVE); - List resources = new ArrayList(); + List resources = new ArrayList<>(); resources.add(r); LockableResourcesManager.get().unreserve(resources); @@ -161,7 +161,7 @@ public void doReset(StaplerRequest req, StaplerResponse rsp) return; } - List resources = new ArrayList(); + List resources = new ArrayList<>(); resources.add(r); LockableResourcesManager.get().reset(resources); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java index 8d7a7d322..272869fbd 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java @@ -42,7 +42,7 @@ public String getUrlName() { public static LockedResourcesBuildAction fromResources( Collection resources) { - List resPojos = new ArrayList(); + List resPojos = new ArrayList<>(); for (LockableResource r : resources) resPojos.add(new ResourcePOJO(r)); return new LockedResourcesBuildAction(resPojos); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java index 88f1fc075..eae1bd6f2 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java @@ -17,7 +17,6 @@ import hudson.model.listeners.RunListener; import hudson.model.StringParameterValue; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -44,7 +43,7 @@ public void onStarted(Run build, TaskListener listener) { if (build instanceof AbstractBuild) { Job proj = Utils.getProject(build); - Set required = new HashSet(); + Set required = new HashSet<>(); if (proj != null) { LockableResourcesStruct resources = Utils.requiredResources(proj); @@ -77,8 +76,6 @@ public void onStarted(Run build, TaskListener listener) { } } } - - return; } @Override @@ -91,7 +88,7 @@ public void onCompleted(Run build, TaskListener listener) { // obviously project name cannot be obtained here List required = LockableResourcesManager.get() .getResourcesFromBuild(build); - if (required.size() > 0) { + if (!required.isEmpty()) { LockableResourcesManager.get().unlock(required, build); listener.getLogger().printf("%s released lock on %s%n", LOG_PREFIX, required); @@ -110,7 +107,7 @@ public void onDeleted(Run build) { List required = LockableResourcesManager.get() .getResourcesFromBuild(build); - if (required.size() > 0) { + if (!required.isEmpty()) { LockableResourcesManager.get().unlock(required, build); LOGGER.fine(build.getFullDisplayName() + " released lock on " + required); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java index 8fb414dee..b651d7b8f 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java @@ -14,7 +14,6 @@ import hudson.Extension; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; -import hudson.model.AbstractProject; import hudson.model.Job; import hudson.model.Queue; import hudson.model.queue.QueueTaskDispatcher; @@ -31,7 +30,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.commons.lang.time.DateUtils; import org.jenkins.plugins.lockableresources.LockableResource; import org.jenkins.plugins.lockableresources.LockableResourcesManager; import org.kohsuke.accmod.Restricted; @@ -73,7 +71,7 @@ public CauseOfBlockage canRun(Queue.Item item) { " trying to get resources with these details: " + resources); if (resourceNumber > 0 || !resources.label.isEmpty() || resources.getResourceMatchScript() != null) { - Map params = new HashMap(); + Map params = new HashMap<>(); // Inject Build Parameters, if possible and applicable to the "item" type try { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index 27b991c1b..5e0014a33 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -9,9 +9,6 @@ package org.jenkins.plugins.lockableresources.queue; import hudson.EnvVars; -import java.io.IOException; -import java.io.ObjectOutputStream; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -40,7 +37,7 @@ public class LockableResourcesStruct implements Serializable { public LockableResourcesStruct(RequiredResourcesProperty property, EnvVars env) { - required = new ArrayList(); + required = new ArrayList<>(); for (String name : property.getResources()) { LockableResource r = LockableResourcesManager.get().fromName( env.expand(name)); @@ -77,7 +74,7 @@ public LockableResourcesStruct(@Nullable List resources, @Nullable Strin } public LockableResourcesStruct(@Nullable List resources, @Nullable String label, int quantity) { - required = new ArrayList(); + required = new ArrayList<>(); if (resources != null) { for (String resource : resources) { LockableResource r = LockableResourcesManager.get().fromName(resource); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java index 8d573ae28..aa5560230 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java @@ -12,9 +12,6 @@ import java.util.List; import org.jenkinsci.plugins.workflow.steps.StepContext; -import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; - -import edu.umd.cs.findbugs.annotations.Nullable; /* * This class is used to queue pipeline contexts diff --git a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java b/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java index 14f66f35c..126f3632b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java @@ -6,7 +6,6 @@ import java.util.concurrent.TimeUnit; import hudson.model.Item; -import hudson.model.ItemGroup; import hudson.model.Queue; import hudson.model.User; import hudson.model.queue.QueueTaskFuture; diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 20f58f853..3364d4eec 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -442,7 +442,7 @@ public void evaluate() throws Throwable { )); FreeStyleProject f = story.j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null)); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); f.getBuildersList().add(new TestBuilder() { @Override @@ -485,7 +485,7 @@ public void evaluate() throws Throwable { isPaused(b1, 1, 0); FreeStyleProject f = story.j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null)); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); f.scheduleBuild2(0); @@ -895,7 +895,7 @@ public void evaluate() throws Throwable { public void run() { try { barrier.await(); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + p.scheduleBuild2(0).waitForStart(); } catch (Exception e) { System.err.println("Failed to start pipeline job"); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java index 04de82092..ccae8a308 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java @@ -26,7 +26,7 @@ import com.gargoylesoftware.htmlunit.AlertHandler; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.html.HtmlButton; +import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.security.FullControlOnceLoggedInAuthorizationStrategy; @@ -81,11 +81,11 @@ public void handleAlert(Page page, String s) { // currently only one button but perhaps in future version of the core/plugin, // other buttons will be added to the layout - List allButtons = htmlPage.getDocumentElement().getHtmlElementsByTagName("button"); + List allButtons = htmlPage.getDocumentElement().getElementsByTagName("button"); assertThat(allButtons.size(), greaterThanOrEqualTo(1)); - HtmlButton reserveButton = null; - for (HtmlButton b : allButtons) { + HtmlElement reserveButton = null; + for (HtmlElement b : allButtons) { String onClick = b.getAttribute("onClick"); if (onClick != null && onClick.contains("reserve_resource")) { reserveButton = b; From d3868e212791261ab888039e8761c830d414113d Mon Sep 17 00:00:00 2001 From: Georgi Hristozov Date: Fri, 24 May 2019 22:54:05 +0300 Subject: [PATCH 0002/1078] Fix a typo: "abel" -> "label" (#115) Noticed the typo on the official Jenkins pipeline docs: https://jenkins.io/doc/pipeline/steps/lockable-resources/ --- .../plugins/lockableresources/LockStep/help-variable.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html index 6331541bc..fb2f46819 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html @@ -5,7 +5,7 @@

e.g.:

-lock(abel: 'label', variable: 'var') {
+lock(label: 'label', variable: 'var') {
     echo "Resource locked: ${env.var}"
 }
 		
From feec254d5bfd7b9681e26743308d485628d493ab Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 24 May 2019 23:01:01 +0200 Subject: [PATCH 0003/1078] Remove old check_licenses.py script --- check_licenses.py | 85 ----------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 check_licenses.py diff --git a/check_licenses.py b/check_licenses.py deleted file mode 100644 index f802aa2f7..000000000 --- a/check_licenses.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/env python - -import os, sys, glob - -JAVA_LICENSE = """\ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (c) 2013, 6WIND S.A. All rights reserved. * - * * - * This file is part of the Jenkins Lockable Resources Plugin and is * - * published under the MIT license. * - * * - * See the "LICENSE.txt" file for more information. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -""" -XML_LICENSE = """\ - -""" - -LICENSED_FILES = { - '.java': JAVA_LICENSE, - '.jelly': XML_LICENSE, - '.xml': XML_LICENSE, -} - -def check_file(file, do_modify): - _, ext = os.path.splitext(file) - missing = 0 - inserted = 0 - if ext in LICENSED_FILES.keys(): - license = LICENSED_FILES[ext] - - with open(file, 'r') as fd: - buffer = fd.read() - - if license not in buffer: - missing = 1 - if do_modify: - with open(file, 'w') as fd: - if buffer.startswith('#!') or buffer.startswith(' 1 and sys.argv[1] == "--modify" - - missing = 0 - inserted = 0 - - for pom in glob.glob('pom.xml'): - miss, ins = check_file(pom, do_modify) - missing += miss - inserted += ins - for source_folder in glob.glob('src'): - for root, dirs, files in os.walk(source_folder): - for file in files: - miss, ins = check_file(os.path.join(root, file), do_modify) - missing += miss - inserted += ins - - print - print missing, "license headers missing.", inserted, "inserted" - - -if __name__ == "__main__": - main() - From 38305bababddcdef35bcca0a5bb4384d329cd8b5 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 24 May 2019 23:19:36 +0200 Subject: [PATCH 0004/1078] Clean up git ignores --- .gitignore | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 6a8ed57db..d01047f3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -target/ -bin/ -work/ -.* -.idea -*.iml +/*.iml +/.idea/ +/target/ +/work/ From b4084083937dcc59cd1b312261460f446bae80ef Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 00:23:17 +0200 Subject: [PATCH 0005/1078] Add editorconfig --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f5250aafb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.{html,java,jelly,xml}] +indent_style = space +indent_size = 2 From bb35e1835a4b76aa562a4197b9e9b103948f9e28 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 17:06:26 +0200 Subject: [PATCH 0006/1078] Split LockStepTest into multiple classes This removes the RestartableJenkinsRule from most of the tests, since only a few of them really need it. --- .../LockStepHardKillTest.java | 166 ++ .../lockableresources/LockStepTest.java | 1912 +++++++---------- .../lockableresources/LockStepTestBase.java | 29 + .../LockStepWithRestartTest.java | 126 ++ 4 files changed, 1079 insertions(+), 1154 deletions(-) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepTestBase.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java new file mode 100644 index 000000000..150cdfa85 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -0,0 +1,166 @@ +package org.jenkins.plugins.lockableresources; + +import static org.junit.Assert.assertNotNull; + +import hudson.model.Executor; +import hudson.model.Result; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; + +public class LockStepHardKillTest extends LockStepTestBase { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Issue("JENKINS-36479") + @Test + public void hardKillNewBuildClearsLock() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + + WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p"); + p1.setDefinition( + new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); + WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); + j.waitForMessage("locked!", b1); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + + // Make sure that b2 is blocked on b1's lock. + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + + // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the + // lock. + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Kill b1 hard. + b1.doKill(); + j.waitForMessage("Hard kill!", b1); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.ABORTED, b1); + + // Verify that b2 gets the lock. + j.waitForMessage("Lock acquired on [resource1]", b2); + SemaphoreStep.success("wait-inside/2", b2); + // Verify that b2 releases the lock and finishes successfully. + j.waitForMessage("Lock released on resource [resource1]", b2); + j.assertBuildStatusSuccess(j.waitForCompletion(b2)); + isPaused(b2, 1, 0); + + // Now b3 should get the lock and do its thing. + j.waitForMessage("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/3", b3); + j.assertBuildStatusSuccess(j.waitForCompletion(b3)); + isPaused(b3, 1, 0); + } + + @Issue("JENKINS-40368") + @Test + public void hardKillWithWaitingRuns() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "retry(99) {\n" + + " lock('resource1') {\n" + + " semaphore('wait-inside')\n" + + " }\n" + + "}", + true)); + + WorkflowRun prevBuild = null; + for (int i = 0; i < 3; i++) { + WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); + if (prevBuild != null) { + j.waitForMessage("[resource1] is locked, waiting...", rNext); + isPaused(rNext, 1, 1); + interruptTermKill(prevBuild); + } + + j.waitForMessage("Lock acquired on [resource1]", rNext); + + SemaphoreStep.waitForStart("wait-inside/" + (i + 1), rNext); + isPaused(rNext, 1, 0); + prevBuild = rNext; + } + SemaphoreStep.success("wait-inside/3", null); + j.assertBuildStatus(Result.SUCCESS, j.waitForCompletion(prevBuild)); + } + + @Issue("JENKINS-40368") + @Test + public void hardKillWithWaitingRunsOnLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "retry(99) {\n" + + " lock(label: 'label1', quantity: 1) {\n" + + " semaphore('wait-inside')\n" + + " }\n" + + "}", + true)); + + WorkflowRun firstPrev = null; + WorkflowRun secondPrev = null; + for (int i = 0; i < 3; i++) { + WorkflowRun firstNext = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("Trying to acquire lock on", firstNext); + WorkflowRun secondNext = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("Trying to acquire lock on", secondNext); + + if (firstPrev != null) { + j.waitForMessage("is locked, waiting...", firstNext); + isPaused(firstNext, 1, 1); + j.waitForMessage("is locked, waiting...", secondNext); + isPaused(secondNext, 1, 1); + } + + interruptTermKill(firstPrev); + j.waitForMessage("Lock acquired on ", firstNext); + interruptTermKill(secondPrev); + j.waitForMessage("Lock acquired on ", secondNext); + + SemaphoreStep.waitForStart("wait-inside/" + ((i * 2) + 1), firstNext); + SemaphoreStep.waitForStart("wait-inside/" + ((i * 2) + 2), secondNext); + isPaused(firstNext, 1, 0); + isPaused(secondNext, 1, 0); + firstPrev = firstNext; + secondPrev = secondNext; + } + SemaphoreStep.success("wait-inside/5", null); + SemaphoreStep.success("wait-inside/6", null); + j.assertBuildStatus(Result.SUCCESS, j.waitForCompletion(firstPrev)); + j.assertBuildStatus(Result.SUCCESS, j.waitForCompletion(secondPrev)); + } + + private void interruptTermKill(WorkflowRun b) throws Exception { + if (b != null) { + Executor ex = b.getExecutor(); + assertNotNull(ex); + ex.interrupt(); + j.waitForMessage("Click here to forcibly terminate running steps", b); + b.doTerm(); + j.waitForMessage("Click here to forcibly kill entire build", b); + b.doKill(); + j.waitForMessage("Hard kill!", b); + j.waitForCompletion(b); + j.assertBuildStatus(Result.ABORTED, b); + } + } +} diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 3364d4eec..52c366d38 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -1,1173 +1,777 @@ package org.jenkins.plugins.lockableresources; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + +import hudson.Functions; +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.FreeStyleProject; +import hudson.model.Result; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.Semaphore; - -import hudson.Functions; -import hudson.model.Executor; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; -import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; -import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import org.jenkinsci.plugins.workflow.support.actions.PauseAction; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.runners.model.Statement; -import org.jvnet.hudson.test.BuildWatcher; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.TestBuilder; import org.jvnet.hudson.test.recipes.WithPlugin; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.FreeStyleBuild; -import hudson.model.FreeStyleProject; -import hudson.model.Result; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; - -public class LockStepTest { - - @Rule - public RestartableJenkinsRule story = new RestartableJenkinsRule(); - - @ClassRule - public static BuildWatcher buildWatcher = new BuildWatcher(); - - @Test - public void autoCreateResource() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " echo 'Resource locked'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - story.j.waitForCompletion(b1); - story.j.assertBuildStatus(Result.SUCCESS, b1); - story.j.assertLogContains("Resource [resource1] did not exist. Created.", b1); - } - }); - } - - @Test - public void lockWithLabel() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', variable: 'var') {\n" + - " echo \"Resource locked: ${env.var}\"\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - story.j.waitForCompletion(b1); - story.j.assertBuildStatus(Result.SUCCESS, b1); - story.j.assertLogContains("Lock released on resource [Label: label1]", b1); - story.j.assertLogContains("Resource locked: resource1", b1); - isPaused(b1, 1, 0); - } - }); - } - - @Test - public void lockOrderLabel() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', quantity: 2) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); - story.j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b2); - isPaused(b2, 1, 1); - WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); - // Both 2 and 3 are waiting for locking Label: label1, Quantity: 2 - story.j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b3); - story.j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b3); - isPaused(b3, 1, 1); - - // Unlock Label: label1, Quantity: 2 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [Label: label1, Quantity: 2]", b1); - isPaused(b1, 1, 0); - - // #2 gets the lock before #3 (in the order as they requested the lock) - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); - SemaphoreStep.success("wait-inside/2", null); - story.j.waitForMessage("Finish", b2); - isPaused(b2, 1, 0); - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b3); - SemaphoreStep.success("wait-inside/3", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockOrderLabelQuantity() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', quantity: 2) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); - story.j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', quantity: 1) {\n" + - " semaphore 'wait-inside-quantity1'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - // While 2 continues waiting, 3 can continue directly - SemaphoreStep.waitForStart("wait-inside-quantity1/1", b3); - // Let 3 finish - SemaphoreStep.success("wait-inside-quantity1/1", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - - // Unlock Label: label1, Quantity: 2 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [Label: label1, Quantity: 2]", b1); - isPaused(b1, 1, 0); - - // #2 gets the lock before #3 (in the order as they requested the lock) - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); - SemaphoreStep.success("wait-inside/2", null); - story.j.waitForMessage("Finish", b2); - isPaused(b2, 1, 0); - } - }); - } - - @Test - public void lockOrderLabelQuantityFreedResources() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1') {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', quantity: 2) {\n" + - " semaphore 'wait-inside-quantity2'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); - story.j.waitForMessage("Found 0 available resource(s). Waiting for correct amount: 2.", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', quantity: 1) {\n" + - " semaphore 'wait-inside-quantity1'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[Label: label1, Quantity: 1] is locked, waiting...", b3); - story.j.waitForMessage("Found 0 available resource(s). Waiting for correct amount: 1.", b3); - isPaused(b3, 1, 1); - - // Unlock Label: label1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [Label: label1]", b1); - isPaused(b1, 1, 0); - - // Both get their lock - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 1]", b3); - - SemaphoreStep.success("wait-inside-quantity2/1", null); - SemaphoreStep.success("wait-inside-quantity1/1", null); - story.j.waitForMessage("Finish", b2); - story.j.waitForMessage("Finish", b3); - isPaused(b2, 1, 0); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockOrder() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); - // Both 2 and 3 are waiting for locking resource1 - - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - - // #2 gets the lock before #3 (in the order as they requested the lock) - story.j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside/2", null); - isPaused(b2, 1, 0); - story.j.waitForMessage("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockInverseOrder() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(resource: 'resource1', inversePrecedence: true) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); - // Both 2 and 3 are waiting for locking resource1 - - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - - // #3 gets the lock before #2 because of inversePrecedence - story.j.waitForMessage("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/2", null); - isPaused(b3, 1, 0); - story.j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside/3", null); - story.j.waitForMessage("Finish", b3); - isPaused(b2, 1, 0); - } - }); - } - - @Test - public void parallelLock() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "parallel a: {\n" + - " sleep 5\n" + - " lock('resource1') {\n" + - " sleep 5\n" + - " }\n" + - "}, b: {\n" + - " lock('resource1') {\n" + - " semaphore 'wait-b'\n" + - " }\n" + - "}\n" - )); - - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-b/1", b1); - // both messages are in the log because branch b acquired the lock and branch a is waiting to lock - story.j.waitForMessage("[b] Lock acquired on [resource1]", b1); - story.j.waitForMessage("[a] [resource1] is locked, waiting...", b1); - isPaused(b1, 2, 1); - - SemaphoreStep.success("wait-b/1", null); - - story.j.waitForMessage("[a] Lock acquired on [resource1]", b1); - isPaused(b1, 2, 0); - } - }); - } - - @Test - public void lockOrderRestart() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); - // Both 2 and 3 are waiting for locking resource1 - - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - } - }); - - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); - WorkflowRun b1 = p.getBuildByNumber(1); - WorkflowRun b2 = p.getBuildByNumber(2); - WorkflowRun b3 = p.getBuildByNumber(3); - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - - story.j.waitForMessage("Lock acquired on [resource1]", b2); - isPaused(b2, 1, 0); - story.j.assertLogContains("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - SemaphoreStep.success("wait-inside/2", null); - SemaphoreStep.waitForStart("wait-inside/3", b3); - story.j.assertLogContains("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void interoperability() { - final Semaphore semaphore = new Semaphore(1); - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " echo 'Locked'\n" + - "}\n" + - "echo 'Finish'" - )); - - FreeStyleProject f = story.j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); - f.getBuildersList().add(new TestBuilder() { - - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - semaphore.acquire(); - return true; - } - - }); - semaphore.acquire(); - f.scheduleBuild2(0).waitForStart(); - - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", b1); - isPaused(b1, 1, 1); - semaphore.release(); - - // Wait for lock after the freestyle finishes - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - } - }); - } - - @Test - public void interoperabilityOnRestart() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - isPaused(b1, 1, 0); - - FreeStyleProject f = story.j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); - - f.scheduleBuild2(0); - - while(story.j.jenkins.getQueue().getItems().length != 1) { - System.out.println("Waiting for freestyle to be queued..."); - Thread.sleep(1000); - } - } - }); - - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); - FreeStyleProject f = story.j.jenkins.getItemByFullName("f", FreeStyleProject.class); - WorkflowRun b1 = p.getBuildByNumber(1); - - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - FreeStyleBuild fb1 = null; - while((fb1 = f.getBuildByNumber(1)) == null) { - System.out.println("Waiting for freestyle #1 to start building..."); - Thread.sleep(1000); - } - - story.j.waitForMessage("acquired lock on [resource1]", fb1); - } - }); - } - - @Issue("JENKINS-36479") - @Test public void hardKillNewBuildClearsLock() throws Exception { - story.addStep(new Statement() { - @Override public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - - WorkflowJob p1 = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p1.setDefinition(new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); - WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("locked!", b1); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}")); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - - // Make sure that b2 is blocked on b1's lock. - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - - // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the lock. - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}")); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Kill b1 hard. - b1.doKill(); - story.j.waitForMessage("Hard kill!", b1); - story.j.waitForCompletion(b1); - story.j.assertBuildStatus(Result.ABORTED, b1); - - - // Verify that b2 gets the lock. - story.j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside/2", b2); - // Verify that b2 releases the lock and finishes successfully. - story.j.waitForMessage("Lock released on resource [resource1]", b2); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b2)); - isPaused(b2, 1, 0); - - // Now b3 should get the lock and do its thing. - story.j.waitForMessage("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", b3); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b3)); - isPaused(b3, 1, 0); - } - }); - } - - // TODO: Figure out what to do about the IOException thrown during clean up, since we don't care about it. It's just - // a result of the first build being deleted and is nothing but noise here. - @Issue("JENKINS-36479") - @Test public void deleteRunningBuildNewBuildClearsLock() throws Exception { - assumeFalse(Functions.isWindows()); // TODO: Investigate failure on Windows. - story.addStep(new Statement() { - @Override public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - - WorkflowJob p1 = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p1.setDefinition(new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); - WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("locked!", b1); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}")); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - - // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the lock. - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}")); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - - - // Make sure that b2 is blocked on b1's lock. - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - b1.delete(); - - - // Verify that b2 gets the lock. - story.j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside/2", b2); - // Verify that b2 releases the lock and finishes successfully. - story.j.waitForMessage("Lock released on resource [resource1]", b2); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b2)); - isPaused(b2, 1, 0); - - // Now b3 should get the lock and do its thing. - story.j.waitForMessage("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", b3); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b3)); - isPaused(b3, 1, 0); - } - }); - } - - @Issue("JENKINS-40368") - @Test - public void hardKillWithWaitingRuns() throws Exception { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition("retry(99) {\n" + - " lock('resource1') {\n" + - " semaphore('wait-inside')\n" + - " }\n" + - "}", true)); - - WorkflowRun prevBuild = null; - for (int i = 0; i < 3; i++) { - WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); - if (prevBuild != null) { - story.j.waitForMessage("[resource1] is locked, waiting...", rNext); - isPaused(rNext, 1, 1); - interruptTermKill(prevBuild); - } - - story.j.waitForMessage("Lock acquired on [resource1]", rNext); - - SemaphoreStep.waitForStart("wait-inside/" + (i + 1), rNext); - isPaused(rNext, 1, 0); - prevBuild = rNext; - } - SemaphoreStep.success("wait-inside/3", null); - story.j.assertBuildStatus(Result.SUCCESS, story.j.waitForCompletion(prevBuild)); - } - }); - } - - @Issue("JENKINS-40368") - @Test - public void hardKillWithWaitingRunsOnLabel() throws Exception { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition("retry(99) {\n" + - " lock(label: 'label1', quantity: 1) {\n" + - " semaphore('wait-inside')\n" + - " }\n" + - "}", true)); - - WorkflowRun firstPrev = null; - WorkflowRun secondPrev = null; - for (int i = 0; i < 3; i++) { - WorkflowRun firstNext = p.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("Trying to acquire lock on", firstNext); - WorkflowRun secondNext = p.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("Trying to acquire lock on", secondNext); - - if (firstPrev != null) { - story.j.waitForMessage("is locked, waiting...", firstNext); - isPaused(firstNext, 1, 1); - story.j.waitForMessage("is locked, waiting...", secondNext); - isPaused(secondNext, 1, 1); - } - - interruptTermKill(firstPrev); - story.j.waitForMessage("Lock acquired on ", firstNext); - interruptTermKill(secondPrev); - story.j.waitForMessage("Lock acquired on ", secondNext); - - SemaphoreStep.waitForStart("wait-inside/" + ((i * 2) + 1), firstNext); - SemaphoreStep.waitForStart("wait-inside/" + ((i * 2) + 2), secondNext); - isPaused(firstNext, 1, 0); - isPaused(secondNext, 1, 0); - firstPrev = firstNext; - secondPrev = secondNext; - } - SemaphoreStep.success("wait-inside/5", null); - SemaphoreStep.success("wait-inside/6", null); - story.j.assertBuildStatus(Result.SUCCESS, story.j.waitForCompletion(firstPrev)); - story.j.assertBuildStatus(Result.SUCCESS, story.j.waitForCompletion(secondPrev)); - } - }); - } - - private void interruptTermKill(WorkflowRun b) throws Exception { - if (b != null) { - Executor ex = b.getExecutor(); - assertNotNull(ex); - ex.interrupt(); - story.j.waitForMessage("Click here to forcibly terminate running steps", b); - b.doTerm(); - story.j.waitForMessage("Click here to forcibly kill entire build", b); - b.doKill(); - story.j.waitForMessage("Hard kill!", b); - story.j.waitForCompletion(b); - story.j.assertBuildStatus(Result.ABORTED, b); - } - } - - @Test - public void unlockButtonWithWaitingRuns() throws Exception { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition("retry(99) {\n" + - " lock('resource1') {\n" + - " semaphore('wait-inside')\n" + - " }\n" + - "}", true)); - - JenkinsRule.WebClient wc = story.j.createWebClient(); - - WorkflowRun prevBuild = null; - for (int i = 0; i < 3; i++) { - WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); - if (prevBuild != null) { - story.j.waitForMessage("[resource1] is locked, waiting...", rNext); - isPaused(rNext, 1, 1); - wc.goTo("lockable-resources/unlock?resource=resource1"); - } - - story.j.waitForMessage("Lock acquired on [resource1]", rNext); - SemaphoreStep.waitForStart("wait-inside/" + (i + 1), rNext); - isPaused(rNext, 1, 0); - - if (prevBuild != null) { - SemaphoreStep.success("wait-inside/" + i, null); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(prevBuild)); - } - prevBuild = rNext; - } - SemaphoreStep.success("wait-inside/3", null); - story.j.assertBuildStatus(Result.SUCCESS, story.j.waitForCompletion(prevBuild)); - } - }); - } - - @Issue("JENKINS-40879") - @Test - public void parallelLockRelease() throws Exception { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - LockableResourcesManager.get().createResource("resource2"); - WorkflowJob j = story.j.jenkins.createProject(WorkflowJob.class, "j"); - j.setDefinition(new CpsFlowDefinition( - "lock(resource: 'resource1') {\n" + - " semaphore 'wait-inside-1'\n" + - "}\n" + - "lock(resource: 'resource2') { \n" + - " echo 'Entering semaphore now'\n" + - " semaphore 'wait-inside-2'\n" + - "}\n", - true)); - - List nextRuns = new ArrayList<>(); - - WorkflowRun toUnlock = null; - for (int i = 0; i < 5; i++) { - WorkflowRun rNext = j.scheduleBuild2(0).waitForStart(); - if (toUnlock != null) { - story.j.waitForMessage("[resource1] is locked, waiting...", rNext); - isPaused(rNext, 1, 1); - SemaphoreStep.success("wait-inside-1/" + i, null); - } - SemaphoreStep.waitForStart("wait-inside-1/" + (i + 1), rNext); - isPaused(rNext, 1, 0); - nextRuns.add(rNext); - toUnlock = rNext; - } - SemaphoreStep.success("wait-inside-1/" + nextRuns.size(), null); - waitAndClear(1, nextRuns); - } - }); - } - - @Issue("JENKINS-34433") - @Test - public void manualUnreserveUnblocksJob() throws Exception { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - JenkinsRule.WebClient wc = story.j.createWebClient(); - - wc.goTo("lockable-resources/reserve?resource=resource1"); - LockableResource resource1 = LockableResourcesManager.get().fromName("resource1"); - assertNotNull(resource1); - resource1.setReservedBy("someone"); - assertTrue(resource1.isReserved()); - - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition("retry(99) {\n" + - " lock('resource1') {\n" + - " semaphore('wait-inside')\n" + - " }\n" + - "}", true)); - - - WorkflowRun r = p.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", r); - wc.goTo("lockable-resources/unreserve?resource=resource1"); - SemaphoreStep.waitForStart("wait-inside/1", r); - SemaphoreStep.success("wait-inside/1", null); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(r)); - } - }); - } - - private void waitAndClear(int semaphoreIndex, List nextRuns) throws Exception { - WorkflowRun toClear = nextRuns.get(0); - - System.err.println("Waiting for semaphore to start for " + toClear.getNumber()); - SemaphoreStep.waitForStart("wait-inside-2/" + semaphoreIndex, toClear); - - List remainingRuns = new ArrayList<>(); - - if (nextRuns.size() > 1) { - remainingRuns.addAll(nextRuns.subList(1, nextRuns.size())); - - for (WorkflowRun r : remainingRuns) { - System.err.println("Verifying no semaphore yet for " + r.getNumber()); - story.j.assertLogNotContains("Entering semaphore now", r); - } - } - - SemaphoreStep.success("wait-inside-2/" + semaphoreIndex, null); - System.err.println("Waiting for " + toClear.getNumber() + " to complete"); - story.j.assertBuildStatusSuccess(story.j.waitForCompletion(toClear)); - - if (!remainingRuns.isEmpty()) { - waitAndClear(semaphoreIndex + 1, remainingRuns); - } - } - - @Test - @WithPlugin("jobConfigHistory.hpi") - public void lockWithLabelConcurrent() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - final WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "import java.util.Random; \n" + - "Random random = new Random(0);\n" + - "lock(label: 'label1') {\n" + - " echo 'Resource locked'\n" + - " sleep random.nextInt(10)*100\n" + - "}\n" + - "echo 'Finish'" - )); - final CyclicBarrier barrier = new CyclicBarrier(51); - for (int i = 0; i < 50; i++) { - Thread thread = new Thread() { - public void run() { - try { - barrier.await(); - p.scheduleBuild2(0).waitForStart(); - } catch (Exception e) { - System.err.println("Failed to start pipeline job"); - } - } - }; - thread.start(); - } - barrier.await(); - story.j.waitUntilNoActivity(); - } - }); - } - - private void isPaused(WorkflowRun run, int count, int effectivePauses) throws Exception { - int pauseActions = 0, pausedActions = 0; - for (FlowNode node : new FlowGraphWalker(run.getExecution())) { - for (PauseAction pauseAction : PauseAction.getPauseActions(node)) { - ++pauseActions; - if (pauseAction.isPaused()) { - ++pausedActions; - } - } - } - assertEquals(count, pauseActions); - assertEquals(effectivePauses, pausedActions); - } - - @Test - public void lockMultipleResources() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(resource: 'resource1', extra: [[resource: 'resource2']]) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside-p2'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock('resource2') {\n" + - " semaphore 'wait-inside-p3'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource2] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Unlock resources - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [{resource1},{resource2},]", b1); - isPaused(b1, 1, 0); - - // Both get their lock - story.j.waitForMessage("Lock acquired on [resource1]", b2); - story.j.waitForMessage("Lock acquired on [resource2]", b3); - - SemaphoreStep.success("wait-inside-p2/1", null); - SemaphoreStep.success("wait-inside-p3/1", null); - story.j.waitForMessage("Finish", b2); - story.j.waitForMessage("Finish", b3); - isPaused(b2, 1, 0); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockWithLabelAndResource() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside-p2'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1') {\n" + - " semaphore 'wait-inside-p3'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[Label: label1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Unlock resources - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); - isPaused(b2, 1, 0); - - // Both get their lock - story.j.waitForMessage("Lock acquired on [resource1]", b2); - story.j.waitForMessage("Lock acquired on [Label: label1]", b3); - - SemaphoreStep.success("wait-inside-p2/1", null); - SemaphoreStep.success("wait-inside-p3/1", null); - story.j.waitForMessage("Finish", b2); - story.j.waitForMessage("Finish", b3); - isPaused(b2, 1, 0); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockWithLabelAndLabeledResource() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside-p2'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1') {\n" + - " semaphore 'wait-inside-p3'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[Label: label1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - - // Unlock resources - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); - isPaused(b1, 1, 0); - - // #2 gets the lock before #3 (in the order as they requested the lock) - story.j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside-p2/1", null); - story.j.waitForMessage("Finish", b2); - isPaused(b2, 1, 0); - story.j.waitForMessage("Lock acquired on [Label: label1]", b3); - SemaphoreStep.success("wait-inside-p3/1", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - } - }); - } - - @Test - public void lockWithLabelAndLabeledResourceQuantity() { - story.addStep(new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); - LockableResourcesManager.get().createResourceWithLabel("resource4", "label1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "lock(resource: 'resource4', variable: 'var', extra: [[resource: 'resource2'], [label: 'label1', quantity: 2]]) {\n" + - " def lockedResources = env.var.split(',')\n" + - " Arrays.sort(lockedResources)\n" + - " echo \"Resources locked: ${lockedResources}\"\n" + - " semaphore 'wait-inside'\n" + - "}\n" + - "echo 'Finish'" - )); - // #1 should lock as few resources as possible - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - - WorkflowJob p2 = story.j.jenkins.createProject(WorkflowJob.class, "p2"); - p2.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', variable: 'var', quantity: 3) {\n" + - " def lockedResources = env.var.split(',')\n" + - " Arrays.sort(lockedResources)\n" + - " echo \"Resources locked: ${lockedResources}\"\n" + - " semaphore 'wait-inside-quantity3'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - story.j.waitForMessage("[Label: label1, Quantity: 3] is locked, waiting...", b2); - story.j.waitForMessage("Found 2 available resource(s). Waiting for correct amount: 3.", b2); - isPaused(b2, 1, 1); - - WorkflowJob p3 = story.j.jenkins.createProject(WorkflowJob.class, "p3"); - p3.setDefinition(new CpsFlowDefinition( - "lock(label: 'label1', variable: 'var', quantity: 2) {\n" + - " def lockedResources = env.var.split(',')\n" + - " Arrays.sort(lockedResources)\n" + - " echo \"Resources locked: ${lockedResources}\"\n" + - " semaphore 'wait-inside-quantity2'\n" + - "}\n" + - "echo 'Finish'" - )); - WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - // While 2 continues waiting, 3 can continue directly - SemaphoreStep.waitForStart("wait-inside-quantity2/1", b3); - // Let 3 finish - SemaphoreStep.success("wait-inside-quantity2/1", null); - story.j.waitForMessage("Finish", b3); - story.j.assertLogContains("Resources locked: [resource1, resource3]", b3); - isPaused(b3, 1, 0); - - // Unlock resources - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [{resource4},{resource2},{Label: label1, Quantity: 2},]", b1); - story.j.assertLogContains("Resources locked: [resource2, resource4]", b1); - isPaused(b1, 1, 0); - - // #2 gets the lock - story.j.waitForMessage("Lock acquired on [Label: label1, Quantity: 3]", b2); - SemaphoreStep.success("wait-inside-quantity3/1", null); - story.j.waitForMessage("Finish", b2); - // Could be any 3 resources, so just check the beginning of the message - story.j.assertLogContains("Resources locked: [resource", b2); - isPaused(b2, 1, 0); - } - }); - } +public class LockStepTest extends LockStepTestBase { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Test + public void autoCreateResource() throws Exception { + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " echo 'Resource locked'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Resource [resource1] did not exist. Created.", b1); + } + + @Test + public void lockWithLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', variable: 'var') {\n" + + " echo \"Resource locked: ${env.var}\"\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Lock released on resource [Label: label1]", b1); + j.assertLogContains("Resource locked: resource1", b1); + isPaused(b1, 1, 0); + } + + @Test + public void lockOrderLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', quantity: 2) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); + j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b2); + isPaused(b2, 1, 1); + WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); + // Both 2 and 3 are waiting for locking Label: label1, Quantity: 2 + j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b3); + j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b3); + isPaused(b3, 1, 1); + + // Unlock Label: label1, Quantity: 2 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [Label: label1, Quantity: 2]", b1); + isPaused(b1, 1, 0); + + // #2 gets the lock before #3 (in the order as they requested the lock) + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); + SemaphoreStep.success("wait-inside/2", null); + j.waitForMessage("Finish", b2); + isPaused(b2, 1, 0); + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b3); + SemaphoreStep.success("wait-inside/3", null); + j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); + } + + @Test + public void lockOrderLabelQuantity() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', quantity: 2) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); + j.waitForMessage("Found 1 available resource(s). Waiting for correct amount: 2.", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', quantity: 1) {\n" + + " semaphore 'wait-inside-quantity1'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + // While 2 continues waiting, 3 can continue directly + SemaphoreStep.waitForStart("wait-inside-quantity1/1", b3); + // Let 3 finish + SemaphoreStep.success("wait-inside-quantity1/1", null); + j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); + + // Unlock Label: label1, Quantity: 2 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [Label: label1, Quantity: 2]", b1); + isPaused(b1, 1, 0); + + // #2 gets the lock before #3 (in the order as they requested the lock) + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); + SemaphoreStep.success("wait-inside/2", null); + j.waitForMessage("Finish", b2); + isPaused(b2, 1, 0); + } + + @Test + public void lockOrderLabelQuantityFreedResources() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', quantity: 2) {\n" + + " semaphore 'wait-inside-quantity2'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); + j.waitForMessage("Found 0 available resource(s). Waiting for correct amount: 2.", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', quantity: 1) {\n" + + " semaphore 'wait-inside-quantity1'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[Label: label1, Quantity: 1] is locked, waiting...", b3); + j.waitForMessage("Found 0 available resource(s). Waiting for correct amount: 1.", b3); + isPaused(b3, 1, 1); + + // Unlock Label: label1 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [Label: label1]", b1); + isPaused(b1, 1, 0); + + // Both get their lock + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 2]", b2); + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 1]", b3); + + SemaphoreStep.success("wait-inside-quantity2/1", null); + SemaphoreStep.success("wait-inside-quantity1/1", null); + j.waitForMessage("Finish", b2); + j.waitForMessage("Finish", b3); + isPaused(b2, 1, 0); + isPaused(b3, 1, 0); + } + + @Test + public void lockOrder() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); + // Both 2 and 3 are waiting for locking resource1 + + j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + + // #2 gets the lock before #3 (in the order as they requested the lock) + j.waitForMessage("Lock acquired on [resource1]", b2); + SemaphoreStep.success("wait-inside/2", null); + isPaused(b2, 1, 0); + j.waitForMessage("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/3", null); + j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); + } + + @Test + public void lockInverseOrder() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(resource: 'resource1', inversePrecedence: true) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); + // Both 2 and 3 are waiting for locking resource1 + + j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + + // #3 gets the lock before #2 because of inversePrecedence + j.waitForMessage("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/2", null); + isPaused(b3, 1, 0); + j.waitForMessage("Lock acquired on [resource1]", b2); + SemaphoreStep.success("wait-inside/3", null); + j.waitForMessage("Finish", b3); + isPaused(b2, 1, 0); + } + + @Test + public void parallelLock() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "parallel a: {\n" + + " sleep 5\n" + + " lock('resource1') {\n" + + " sleep 5\n" + + " }\n" + + "}, b: {\n" + + " lock('resource1') {\n" + + " semaphore 'wait-b'\n" + + " }\n" + + "}\n")); + + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-b/1", b1); + // both messages are in the log because branch b acquired the lock and branch a is waiting to + // lock + j.waitForMessage("[b] Lock acquired on [resource1]", b1); + j.waitForMessage("[a] [resource1] is locked, waiting...", b1); + isPaused(b1, 2, 1); + + SemaphoreStep.success("wait-b/1", null); + + j.waitForMessage("[a] Lock acquired on [resource1]", b1); + isPaused(b1, 2, 0); + } + + @Test + public void interoperability() throws Exception { + final Semaphore semaphore = new Semaphore(1); + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " echo 'Locked'\n" + "}\n" + "echo 'Finish'")); + + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + f.getBuildersList() + .add( + new TestBuilder() { + + @Override + public boolean perform( + AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { + semaphore.acquire(); + return true; + } + }); + semaphore.acquire(); + f.scheduleBuild2(0).waitForStart(); + + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b1); + isPaused(b1, 1, 1); + semaphore.release(); + + // Wait for lock after the freestyle finishes + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + } + + // TODO: Figure out what to do about the IOException thrown during clean up, since we don't care + // about it. It's just + // a result of the first build being deleted and is nothing but noise here. + @Issue("JENKINS-36479") + @Test + public void deleteRunningBuildNewBuildClearsLock() throws Exception { + assumeFalse(Functions.isWindows()); // TODO: Investigate failure on Windows. + + LockableResourcesManager.get().createResource("resource1"); + + WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p"); + p1.setDefinition( + new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); + WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); + j.waitForMessage("locked!", b1); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + + // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the lock. + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + + // Make sure that b2 is blocked on b1's lock. + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + b1.delete(); + + // Verify that b2 gets the lock. + j.waitForMessage("Lock acquired on [resource1]", b2); + SemaphoreStep.success("wait-inside/2", b2); + // Verify that b2 releases the lock and finishes successfully. + j.waitForMessage("Lock released on resource [resource1]", b2); + j.assertBuildStatusSuccess(j.waitForCompletion(b2)); + isPaused(b2, 1, 0); + + // Now b3 should get the lock and do its thing. + j.waitForMessage("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/3", b3); + j.assertBuildStatusSuccess(j.waitForCompletion(b3)); + isPaused(b3, 1, 0); + } + + @Test + public void unlockButtonWithWaitingRuns() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "retry(99) {\n" + + " lock('resource1') {\n" + + " semaphore('wait-inside')\n" + + " }\n" + + "}", + true)); + + JenkinsRule.WebClient wc = j.createWebClient(); + + WorkflowRun prevBuild = null; + for (int i = 0; i < 3; i++) { + WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); + if (prevBuild != null) { + j.waitForMessage("[resource1] is locked, waiting...", rNext); + isPaused(rNext, 1, 1); + wc.goTo("lockable-resources/unlock?resource=resource1"); + } + + j.waitForMessage("Lock acquired on [resource1]", rNext); + SemaphoreStep.waitForStart("wait-inside/" + (i + 1), rNext); + isPaused(rNext, 1, 0); + + if (prevBuild != null) { + SemaphoreStep.success("wait-inside/" + i, null); + j.assertBuildStatusSuccess(j.waitForCompletion(prevBuild)); + } + prevBuild = rNext; + } + SemaphoreStep.success("wait-inside/3", null); + j.assertBuildStatus(Result.SUCCESS, j.waitForCompletion(prevBuild)); + } + + @Issue("JENKINS-40879") + @Test + public void parallelLockRelease() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + LockableResourcesManager.get().createResource("resource2"); + WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "j"); + job.setDefinition( + new CpsFlowDefinition( + "lock(resource: 'resource1') {\n" + + " semaphore 'wait-inside-1'\n" + + "}\n" + + "lock(resource: 'resource2') { \n" + + " echo 'Entering semaphore now'\n" + + " semaphore 'wait-inside-2'\n" + + "}\n", + true)); + + List nextRuns = new ArrayList<>(); + + WorkflowRun toUnlock = null; + for (int i = 0; i < 5; i++) { + WorkflowRun rNext = job.scheduleBuild2(0).waitForStart(); + if (toUnlock != null) { + j.waitForMessage("[resource1] is locked, waiting...", rNext); + isPaused(rNext, 1, 1); + SemaphoreStep.success("wait-inside-1/" + i, null); + } + SemaphoreStep.waitForStart("wait-inside-1/" + (i + 1), rNext); + isPaused(rNext, 1, 0); + nextRuns.add(rNext); + toUnlock = rNext; + } + SemaphoreStep.success("wait-inside-1/" + nextRuns.size(), null); + waitAndClear(1, nextRuns); + } + + @Issue("JENKINS-34433") + @Test + public void manualUnreserveUnblocksJob() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + JenkinsRule.WebClient wc = j.createWebClient(); + + wc.goTo("lockable-resources/reserve?resource=resource1"); + LockableResource resource1 = LockableResourcesManager.get().fromName("resource1"); + assertNotNull(resource1); + resource1.setReservedBy("someone"); + assertTrue(resource1.isReserved()); + + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "retry(99) {\n" + + " lock('resource1') {\n" + + " semaphore('wait-inside')\n" + + " }\n" + + "}", + true)); + + WorkflowRun r = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", r); + wc.goTo("lockable-resources/unreserve?resource=resource1"); + SemaphoreStep.waitForStart("wait-inside/1", r); + SemaphoreStep.success("wait-inside/1", null); + j.assertBuildStatusSuccess(j.waitForCompletion(r)); + } + + private void waitAndClear(int semaphoreIndex, List nextRuns) throws Exception { + WorkflowRun toClear = nextRuns.get(0); + + System.err.println("Waiting for semaphore to start for " + toClear.getNumber()); + SemaphoreStep.waitForStart("wait-inside-2/" + semaphoreIndex, toClear); + + List remainingRuns = new ArrayList<>(); + + if (nextRuns.size() > 1) { + remainingRuns.addAll(nextRuns.subList(1, nextRuns.size())); + + for (WorkflowRun r : remainingRuns) { + System.err.println("Verifying no semaphore yet for " + r.getNumber()); + j.assertLogNotContains("Entering semaphore now", r); + } + } + + SemaphoreStep.success("wait-inside-2/" + semaphoreIndex, null); + System.err.println("Waiting for " + toClear.getNumber() + " to complete"); + j.assertBuildStatusSuccess(j.waitForCompletion(toClear)); + + if (!remainingRuns.isEmpty()) { + waitAndClear(semaphoreIndex + 1, remainingRuns); + } + } + + @Test + @WithPlugin("jobConfigHistory.hpi") + public void lockWithLabelConcurrent() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + final WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "import java.util.Random; \n" + + "Random random = new Random(0);\n" + + "lock(label: 'label1') {\n" + + " echo 'Resource locked'\n" + + " sleep random.nextInt(10)*100\n" + + "}\n" + + "echo 'Finish'")); + final CyclicBarrier barrier = new CyclicBarrier(51); + for (int i = 0; i < 50; i++) { + Thread thread = + new Thread() { + public void run() { + try { + barrier.await(); + p.scheduleBuild2(0).waitForStart(); + } catch (Exception e) { + System.err.println("Failed to start pipeline job"); + } + } + }; + thread.start(); + } + barrier.await(); + j.waitUntilNoActivity(); + } + + @Test + public void lockMultipleResources() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(resource: 'resource1', extra: [[resource: 'resource2']]) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock('resource2') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource2] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [{resource1},{resource2},]", b1); + isPaused(b1, 1, 0); + + // Both get their lock + j.waitForMessage("Lock acquired on [resource1]", b2); + j.waitForMessage("Lock acquired on [resource2]", b3); + + SemaphoreStep.success("wait-inside-p2/1", null); + SemaphoreStep.success("wait-inside-p3/1", null); + j.waitForMessage("Finish", b2); + j.waitForMessage("Finish", b3); + isPaused(b2, 1, 0); + isPaused(b3, 1, 0); + } + + @Test + public void lockWithLabelAndResource() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1') {\n" + + " semaphore 'wait-inside-p3'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[Label: label1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); + isPaused(b2, 1, 0); + + // Both get their lock + j.waitForMessage("Lock acquired on [resource1]", b2); + j.waitForMessage("Lock acquired on [Label: label1]", b3); + + SemaphoreStep.success("wait-inside-p2/1", null); + SemaphoreStep.success("wait-inside-p3/1", null); + j.waitForMessage("Finish", b2); + j.waitForMessage("Finish", b3); + isPaused(b2, 1, 0); + isPaused(b3, 1, 0); + } + + @Test + public void lockWithLabelAndLabeledResource() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1') {\n" + + " semaphore 'wait-inside-p3'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[Label: label1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); + isPaused(b1, 1, 0); + + // #2 gets the lock before #3 (in the order as they requested the lock) + j.waitForMessage("Lock acquired on [resource1]", b2); + SemaphoreStep.success("wait-inside-p2/1", null); + j.waitForMessage("Finish", b2); + isPaused(b2, 1, 0); + j.waitForMessage("Lock acquired on [Label: label1]", b3); + SemaphoreStep.success("wait-inside-p3/1", null); + j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); + } + + @Test + public void lockWithLabelAndLabeledResourceQuantity() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource3", "label1"); + LockableResourcesManager.get().createResourceWithLabel("resource4", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(resource: 'resource4', variable: 'var', extra: [[resource: 'resource2'], [label: 'label1', quantity: 2]]) {\n" + + " def lockedResources = env.var.split(',')\n" + + " Arrays.sort(lockedResources)\n" + + " echo \"Resources locked: ${lockedResources}\"\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + // #1 should lock as few resources as possible + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', variable: 'var', quantity: 3) {\n" + + " def lockedResources = env.var.split(',')\n" + + " Arrays.sort(lockedResources)\n" + + " echo \"Resources locked: ${lockedResources}\"\n" + + " semaphore 'wait-inside-quantity3'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[Label: label1, Quantity: 3] is locked, waiting...", b2); + j.waitForMessage("Found 2 available resource(s). Waiting for correct amount: 3.", b2); + isPaused(b2, 1, 1); + + WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); + p3.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', variable: 'var', quantity: 2) {\n" + + " def lockedResources = env.var.split(',')\n" + + " Arrays.sort(lockedResources)\n" + + " echo \"Resources locked: ${lockedResources}\"\n" + + " semaphore 'wait-inside-quantity2'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); + // While 2 continues waiting, 3 can continue directly + SemaphoreStep.waitForStart("wait-inside-quantity2/1", b3); + // Let 3 finish + SemaphoreStep.success("wait-inside-quantity2/1", null); + j.waitForMessage("Finish", b3); + j.assertLogContains("Resources locked: [resource1, resource3]", b3); + isPaused(b3, 1, 0); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage( + "Lock released on resource [{resource4},{resource2},{Label: label1, Quantity: 2},]", b1); + j.assertLogContains("Resources locked: [resource2, resource4]", b1); + isPaused(b1, 1, 0); + + // #2 gets the lock + j.waitForMessage("Lock acquired on [Label: label1, Quantity: 3]", b2); + SemaphoreStep.success("wait-inside-quantity3/1", null); + j.waitForMessage("Finish", b2); + // Could be any 3 resources, so just check the beginning of the message + j.assertLogContains("Resources locked: [resource", b2); + isPaused(b2, 1, 0); + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTestBase.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTestBase.java new file mode 100644 index 000000000..dda06f56c --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTestBase.java @@ -0,0 +1,29 @@ +package org.jenkins.plugins.lockableresources; + +import static org.junit.Assert.assertEquals; + +import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; +import org.jenkinsci.plugins.workflow.graph.FlowNode; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.support.actions.PauseAction; +import org.junit.ClassRule; +import org.jvnet.hudson.test.BuildWatcher; + +public class LockStepTestBase { + + @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); + + protected void isPaused(WorkflowRun run, int count, int effectivePauses) { + int pauseActions = 0, pausedActions = 0; + for (FlowNode node : new FlowGraphWalker(run.getExecution())) { + for (PauseAction pauseAction : PauseAction.getPauseActions(node)) { + ++pauseActions; + if (pauseAction.isPaused()) { + ++pausedActions; + } + } + } + assertEquals(count, pauseActions); + assertEquals(effectivePauses, pausedActions); + } +} diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java new file mode 100644 index 000000000..717003850 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -0,0 +1,126 @@ +package org.jenkins.plugins.lockableresources; + +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runners.model.Statement; +import org.jvnet.hudson.test.RestartableJenkinsRule; + +public class LockStepWithRestartTest extends LockStepTestBase { + + @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); + + @Test + public void lockOrderRestart() { + story.addStep( + new Statement() { + @Override + public void evaluate() throws Throwable { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + story.j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); + // Both 2 and 3 are waiting for locking resource1 + + story.j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + } + }); + + story.addStep( + new Statement() { + @Override + public void evaluate() throws Throwable { + WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); + WorkflowRun b1 = p.getBuildByNumber(1); + WorkflowRun b2 = p.getBuildByNumber(2); + WorkflowRun b3 = p.getBuildByNumber(3); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + story.j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + + story.j.waitForMessage("Lock acquired on [resource1]", b2); + isPaused(b2, 1, 0); + story.j.assertLogContains("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + SemaphoreStep.success("wait-inside/2", null); + SemaphoreStep.waitForStart("wait-inside/3", b3); + story.j.assertLogContains("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/3", null); + story.j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); + } + }); + } + + @Test + public void interoperabilityOnRestart() { + story.addStep( + new Statement() { + @Override + public void evaluate() throws Throwable { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + isPaused(b1, 1, 0); + + FreeStyleProject f = story.j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + + f.scheduleBuild2(0); + + while (story.j.jenkins.getQueue().getItems().length != 1) { + System.out.println("Waiting for freestyle to be queued..."); + Thread.sleep(1000); + } + } + }); + + story.addStep( + new Statement() { + @Override + public void evaluate() throws Throwable { + WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); + FreeStyleProject f = story.j.jenkins.getItemByFullName("f", FreeStyleProject.class); + WorkflowRun b1 = p.getBuildByNumber(1); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + story.j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + FreeStyleBuild fb1 = null; + while ((fb1 = f.getBuildByNumber(1)) == null) { + System.out.println("Waiting for freestyle #1 to start building..."); + Thread.sleep(1000); + } + + story.j.waitForMessage("acquired lock on [resource1]", fb1); + } + }); + } +} From 3b657280dcc2d08e7e48020f2aee5911e849aba2 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 17:12:19 +0200 Subject: [PATCH 0007/1078] Disable tests which fail on Java 11 --- .../lockableresources/LockStepWithRestartTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 717003850..10aa6c11d 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -1,11 +1,14 @@ package org.jenkins.plugins.lockableresources; +import static org.junit.Assume.assumeFalse; + import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runners.model.Statement; @@ -15,6 +18,12 @@ public class LockStepWithRestartTest extends LockStepTestBase { @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); + @Before + public void disableOnNewerJava() { + // FIXME: These tests break on Java 11 + assumeFalse(Double.parseDouble(System.getProperty("java.specification.version", "1.8")) > 10.0); + } + @Test public void lockOrderRestart() { story.addStep( From 86fc7c4eac38aadcae5ff037e67d2ffbd09fff69 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 17:35:34 +0200 Subject: [PATCH 0008/1078] Clean up and format pom.xml --- pom.xml | 306 +++++++++++++++++++++++++++----------------------------- 1 file changed, 145 insertions(+), 161 deletions(-) diff --git a/pom.xml b/pom.xml index 27fbdb91a..82dd1a9f3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,172 +1,156 @@ - - - 4.0.0 - - org.jenkins-ci.plugins - plugin - 3.37 - - + + + 4.0.0 - org.6wind.jenkins - lockable-resources - 2.6-SNAPSHOT - hpi - Lockable Resources plugin - - This plugin allows to define lockable resources (such as printers, phones, - computers) that can be used by builds. If a build requires an external - resource which is already locked, it will wait for the resource to be free. - - https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin + + org.jenkins-ci.plugins + plugin + 3.37 + + - - 8 - 2.12 - 2.60.3 - + org.6wind.jenkins + lockable-resources + 2.6-SNAPSHOT + hpi - - - MIT - http://www.opensource.org/licenses/mit-license.php - - + Lockable Resources plugin + + This plugin allows to define lockable resources (such as printers, phones, + computers) that can be used by builds. If a build requires an external + resource which is already locked, it will wait for the resource to be free. + + https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin + 2013 + + + MIT + https://opensource.org/licenses/MIT + + - - - robin-jarry - Robin Jarry - robin.jarry@6wind.com - - developer - maintainer - - CET - - - amuniz - Antonio Muñiz - amuniz@cloudbees.com - - developer - maintainer - - CET - - + + + TobiX + Tobias Gruetzmacher + tobias-git@23.gs + + + amuniz + Antonio Muñiz + amuniz@cloudbees.com + + - - - org.jenkins-ci.plugins - mailer - 1.13 - - - org.jenkins-ci.plugins.workflow - workflow-support - ${workflow-support.version} - - - org.jenkins-ci.plugins - matrix-project - 1.4 - - - org.jenkins-ci.plugins - script-security - 1.33 - - - com.infradna.tool - bridge-method-annotation - 1.14 - provided - - - org.jenkins-ci - annotation-indexer - - - + + scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git + scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git + https://github.com/jenkinsci/lockable-resources-plugin + HEAD + - - - org.jenkins-ci.plugins.workflow - workflow-support - ${workflow-support.version} - tests - test - - - org.jenkins-ci.plugins.workflow - workflow-basic-steps - 2.2 - test - - - org.jenkins-ci.plugins.workflow - workflow-cps - 2.10 - test - - - org.jenkins-ci.plugins.workflow - workflow-job - 2.0 - test - - + + 8 + 2.12 + 2.60.3 + - - - - org.jenkins-ci.tools - maven-hpi-plugin - - - FINE - - 2.0 - - - - maven-release-plugin - - false - - - - + + + org.jenkins-ci.plugins + mailer + 1.13 + + + org.jenkins-ci.plugins.workflow + workflow-support + ${workflow-support.version} + + + org.jenkins-ci.plugins + matrix-project + 1.4 + + + org.jenkins-ci.plugins + script-security + 1.33 + + + com.infradna.tool + bridge-method-annotation + 1.14 + provided + + + org.jenkins-ci + annotation-indexer + + + - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - + + + org.jenkins-ci.plugins.workflow + workflow-support + ${workflow-support.version} + tests + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + 2.2 + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + 2.10 + test + + + org.jenkins-ci.plugins.workflow + workflow-job + 2.0 + test + + - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git - scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git - https://github.com/jenkinsci/lockable-resources-plugin - HEAD - + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + + com.coveo + fmt-maven-plugin + 2.9 + + + + + + org.jenkins-ci.tools + maven-hpi-plugin + + + FINE + + 2.0 + + + + From c6b0b4cab3fbdcc35d9c6819fdf2e4277d7111ab Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 17:52:16 +0200 Subject: [PATCH 0009/1078] Speed up tests by running them in parallel --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index 82dd1a9f3..5a39fdd6d 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,8 @@ 8 2.12 2.60.3 + + 1C From e2f5c532423b860e745d165642ff4cf222225e0e Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 18:11:30 +0200 Subject: [PATCH 0010/1078] Add useful info to README and LICENSE --- LICENSE.txt | 4 +++- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 79e40d7ee..a73259d71 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,8 @@ The MIT License -Copyright (c) 2013, 6WIND S.A. All rights reserved. +Copyright 2013-2015, 6WIND S.A. All rights reserved. +Copyright 2016-2018, Antonio Muñiz +Copyright 2019, TobiX Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b8072fbda..73fe82cf4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,53 @@ # Jenkins Lockable Resources Plugin +[![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) +[![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) +[![Maintenance](https://img.shields.io/maintenance/yes/2019.svg)]() + This plugins allows to define "lockable resources" in the global configuration. These resources can then be "required" by jobs. If a job requires a resource which is already locked, it will be put in queue until the resource is released. + +## Contributing + +If you want to contribute to this plugin, you probably will need a Jenkins plugin developement +environment. This basically means a current version of Java (Java 8 should probably be okay for now) +and [Apache Maven]. See the [Jenkins Plugin Tutorial] for details. + +If you have the proper environment, typing: + + $ mvn verify + +should create a plugin as `target/*.hpi`, which you can install in your Jenkins instance. Running + + $ mvn hpi:run -Djenkins.version=2.164.1 + +allows you to spin up a test Jenkins instance on [localhost] to test your +local changes before commiting. + +[Apache Maven]: https://maven.apache.org/ +[Jenkins Plugin Tutorial]: https://jenkins.io/doc/developer/tutorial/prepare/ +[localhost]: http://localhost:8080/jenkins/ + +### Code Style + +This plugin tries to migrate to [Google Java Code Style], please try to adhere to that style +whenever adding new files or making big changes to existing files. If your IDE doesn't support +this style, you can use the [fmt-maven-plugin], like this: + + $ mvn fmt:format -DfilesNamePattern=ChangedFile\.java + +to reformat Java code in the proper style. + +[Google Java Code Style]: https://google.github.io/styleguide/javaguide.html +[fmt-maven-plugin]: https://github.com/coveo/fmt-maven-plugin + +## License + +The MIT License (MIT) + +- Copyright 2013-2015 6WIND +- Copyright 2016-2018 Antonio Muñiz +- Copyright 2019 TobiX + +See [LICENSE](LICENSE.txt) From 1406b5942dff6d6bd4b045585aa5af2909a15c59 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 20:16:09 +0200 Subject: [PATCH 0011/1078] Make overview page use all available space We use the one-column layout and don't restrict the table width. --- .../LockableResourcesRootAction/index.jelly | 272 +++++++++--------- 1 file changed, 130 insertions(+), 142 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 0acf38d6d..5342ed767 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -1,147 +1,135 @@ - - - - -

${%Lockable Resources}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ResourceStatusLabelsAction
- ${resource.name}
- ${resource.description} -
- LOCKED by - - ${resource.build.fullDisplayName} - - ${resource.labels} - - - - - RESERVED by ${resource.reservedBy} - ${resource.labels} - - - - - - - QUEUED by "${resource.queueItemProject} ${resource.queueItemId}" - ${resource.labels} - - - - - FREE - ${resource.labels} - - - -
- -

Labels

- - - - - - - - - - - - - - - - - - - - - - - - - -
LabelFree resources
${label}0${label}1${label}${it.getFreeResourceAmount(label)}
-
+ + -
-
+ + +

${%Lockable Resources}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResourceStatusLabelsAction
+ ${resource.name} +
+ ${resource.description} +
+ LOCKED + by + + ${resource.build.fullDisplayName} + + ${resource.labels} + + + + + RESERVED + by + ${resource.reservedBy} + ${resource.labels} + + + + + + + QUEUED by "${resource.queueItemProject} ${resource.queueItemId}" + ${resource.labels} + + + + + FREE + ${resource.labels} + + + +
+ +

Labels

+ + + + + + + + + + + + + + + + + + + + + + + + + +
LabelFree resources
${label}0${label}1${label}${it.getFreeResourceAmount(label)}
+
+
+
From 0996b84163184972acdbed145e7d979238aca7a3 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 20:37:21 +0200 Subject: [PATCH 0012/1078] Fix test after layout change --- .../LockableResourceRootActionSEC1361Test.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java index ccae8a308..659951167 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java @@ -23,6 +23,11 @@ */ package org.jenkins.plugins.lockableresources; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertThat; + import com.gargoylesoftware.htmlunit.AlertHandler; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; @@ -30,19 +35,13 @@ import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.security.FullControlOnceLoggedInAuthorizationStrategy; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.Assert.assertThat; - public class LockableResourceRootActionSEC1361Test { @Rule @@ -87,7 +86,7 @@ public void handleAlert(Page page, String s) { HtmlElement reserveButton = null; for (HtmlElement b : allButtons) { String onClick = b.getAttribute("onClick"); - if (onClick != null && onClick.contains("reserve_resource")) { + if (onClick != null && onClick.contains("reserve")) { reserveButton = b; } } From 3663aba194c19e6593f297e76618a8d2d986038b Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 25 May 2019 20:39:11 +0200 Subject: [PATCH 0013/1078] Incrementalified. --- .mvn/extensions.xml | 7 +++++++ .mvn/maven.config | 2 ++ pom.xml | 8 +++++--- 3 files changed, 14 insertions(+), 3 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 000000000..94863e605 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.0-beta-7 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 000000000..2a0299c48 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals diff --git a/pom.xml b/pom.xml index 5a39fdd6d..2ba2ee053 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ org.jenkins-ci.plugins plugin - 3.37 + 3.43 org.6wind.jenkins lockable-resources - 2.6-SNAPSHOT + ${revision}${changelist} hpi Lockable Resources plugin @@ -46,10 +46,12 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - HEAD + ${scmTag} + 2.6 + -SNAPSHOT 8 2.12 2.60.3 From 751d70d3ae6068edd233a8144c63d9e2422ad829 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Wed, 29 May 2019 02:18:29 -0400 Subject: [PATCH 0014/1078] [JENKINS-55787] Switch labels from entry to checkbox (#125) --- .../jenkins/plugins/lockableresources/LockStep/config.jelly | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly index 90affe3e7..1faabfafd 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly @@ -13,8 +13,8 @@ - - + + From fae1c310fce9a3d2738cb30a7e472b299ce0f273 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Thu, 6 Jun 2019 00:40:42 +0200 Subject: [PATCH 0015/1078] Add another test with Jenkins restart --- .../LockStepWithRestartTest.java | 211 ++++++++++-------- 1 file changed, 117 insertions(+), 94 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 10aa6c11d..6d1d78dc7 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -4,6 +4,7 @@ import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; +import java.util.Collections; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; @@ -11,7 +12,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.runners.model.Statement; +import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.RestartableJenkinsRule; public class LockStepWithRestartTest extends LockStepTestBase { @@ -26,110 +27,132 @@ public void disableOnNewerJava() { @Test public void lockOrderRestart() { - story.addStep( - new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition( - new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}\n" - + "echo 'Finish'")); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); - // Ensure that b2 reaches the lock before b3 - story.j.waitForMessage("[resource1] is locked, waiting...", b2); - isPaused(b2, 1, 1); - WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); - // Both 2 and 3 are waiting for locking resource1 - - story.j.waitForMessage("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - } + story.then( + (JenkinsRule j) -> { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); + // Ensure that b2 reaches the lock before b3 + j.waitForMessage("[resource1] is locked, waiting...", b2); + isPaused(b2, 1, 1); + WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); + // Both 2 and 3 are waiting for locking resource1 + + j.waitForMessage("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); }); - story.addStep( - new Statement() { - @Override - public void evaluate() throws Throwable { - WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); - WorkflowRun b1 = p.getBuildByNumber(1); - WorkflowRun b2 = p.getBuildByNumber(2); - WorkflowRun b3 = p.getBuildByNumber(3); - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - - story.j.waitForMessage("Lock acquired on [resource1]", b2); - isPaused(b2, 1, 0); - story.j.assertLogContains("[resource1] is locked, waiting...", b3); - isPaused(b3, 1, 1); - SemaphoreStep.success("wait-inside/2", null); - SemaphoreStep.waitForStart("wait-inside/3", b3); - story.j.assertLogContains("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", null); - story.j.waitForMessage("Finish", b3); - isPaused(b3, 1, 0); - } + story.then( + (JenkinsRule j) -> { + WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); + WorkflowRun b1 = p.getBuildByNumber(1); + WorkflowRun b2 = p.getBuildByNumber(2); + WorkflowRun b3 = p.getBuildByNumber(3); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + + j.waitForMessage("Lock acquired on [resource1]", b2); + isPaused(b2, 1, 0); + j.assertLogContains("[resource1] is locked, waiting...", b3); + isPaused(b3, 1, 1); + SemaphoreStep.success("wait-inside/2", null); + SemaphoreStep.waitForStart("wait-inside/3", b3); + j.assertLogContains("Lock acquired on [resource1]", b3); + SemaphoreStep.success("wait-inside/3", null); + j.waitForMessage("Finish", b3); + isPaused(b3, 1, 0); }); } @Test public void interoperabilityOnRestart() { - story.addStep( - new Statement() { - @Override - public void evaluate() throws Throwable { - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition( - new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}\n" - + "echo 'Finish'")); - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - SemaphoreStep.waitForStart("wait-inside/1", b1); - isPaused(b1, 1, 0); - - FreeStyleProject f = story.j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); - - f.scheduleBuild2(0); - - while (story.j.jenkins.getQueue().getItems().length != 1) { - System.out.println("Waiting for freestyle to be queued..."); - Thread.sleep(1000); - } + story.then( + (JenkinsRule j) -> { + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + isPaused(b1, 1, 0); + + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + + f.scheduleBuild2(0); + + while (j.jenkins.getQueue().getItems().length != 1) { + System.out.println("Waiting for freestyle to be queued..."); + Thread.sleep(1000); } }); - story.addStep( - new Statement() { - @Override - public void evaluate() throws Throwable { - WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class); - FreeStyleProject f = story.j.jenkins.getItemByFullName("f", FreeStyleProject.class); - WorkflowRun b1 = p.getBuildByNumber(1); - - // Unlock resource1 - SemaphoreStep.success("wait-inside/1", null); - story.j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - FreeStyleBuild fb1 = null; - while ((fb1 = f.getBuildByNumber(1)) == null) { - System.out.println("Waiting for freestyle #1 to start building..."); - Thread.sleep(1000); - } - - story.j.waitForMessage("acquired lock on [resource1]", fb1); + story.then( + (JenkinsRule j) -> { + WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); + FreeStyleProject f = j.jenkins.getItemByFullName("f", FreeStyleProject.class); + WorkflowRun b1 = p.getBuildByNumber(1); + + // Unlock resource1 + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + FreeStyleBuild fb1 = null; + while ((fb1 = f.getBuildByNumber(1)) == null) { + System.out.println("Waiting for freestyle #1 to start building..."); + Thread.sleep(1000); } + + j.waitForMessage("acquired lock on [resource1]", fb1); + }); + } + + @Test + public void testReserveOverRestart() { + story.then( + (JenkinsRule j) -> { + LockableResourcesManager manager = LockableResourcesManager.get(); + manager.createResource("resource1"); + manager.fromName("resource1").setReservedBy("user"); + manager.save(); + + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " echo 'inside'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked, waiting...", b1); + isPaused(b1, 1, 1); + }); + + story.then( + (JenkinsRule j) -> { + WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); + WorkflowRun b1 = p.getBuildByNumber(1); + + LockableResourcesManager manager = LockableResourcesManager.get(); + manager.createResource("resource1"); + manager.unreserve(Collections.singletonList(manager.fromName("resource1"))); + + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + j.waitForMessage("Finish", b1); + isPaused(b1, 1, 0); }); } } From 7592e27248872c576a42e6de43986b987a66ff12 Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Fri, 5 Jul 2019 10:11:24 +0300 Subject: [PATCH 0016/1078] Add test for autocreate resource in FreeStyle project --- .../lockableresources/LockStepTest.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 52c366d38..443055c8f 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -6,10 +6,7 @@ import hudson.Functions; import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.FreeStyleProject; -import hudson.model.Result; +import hudson.model.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -42,6 +39,27 @@ public void autoCreateResource() throws Exception { j.assertLogContains("Resource [resource1] did not exist. Created.", b1); } + @Test + public void autoCreateResourceFreeStyle() throws IOException, InterruptedException { + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + + f.scheduleBuild2(0); + + while (j.jenkins.getQueue().getItems().length != 1) { + System.out.println("Waiting for freestyle to be queued..."); + Thread.sleep(1000); + } + + FreeStyleBuild fb1 = null; + while ((fb1 = f.getBuildByNumber(1)) == null) { + System.out.println("Waiting for freestyle #1 to start building..."); + Thread.sleep(1000); + } + + j.waitForMessage("acquired lock on [resource1]", fb1); + } + @Test public void lockWithLabel() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); From 693c67f033a2f53a5bbe34973b7b580b7c24382e Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Fri, 5 Jul 2019 10:11:31 +0300 Subject: [PATCH 0017/1078] mvn fmt:format -DfilesNamePattern=LockableResourcesStruct.java --- .../queue/LockableResourcesStruct.java | 206 +++++++++--------- 1 file changed, 105 insertions(+), 101 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index 5e0014a33..08e8b8a27 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -8,118 +8,122 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package org.jenkins.plugins.lockableresources.queue; +import edu.umd.cs.findbugs.annotations.Nullable; import hudson.EnvVars; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.annotation.CheckForNull; - import org.jenkins.plugins.lockableresources.LockableResource; import org.jenkins.plugins.lockableresources.LockableResourcesManager; import org.jenkins.plugins.lockableresources.RequiredResourcesProperty; import org.jenkins.plugins.lockableresources.util.SerializableSecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; -import edu.umd.cs.findbugs.annotations.Nullable; - public class LockableResourcesStruct implements Serializable { - public List required; - public String label; - public String requiredVar; - public String requiredNumber; - - @CheckForNull - private final SerializableSecureGroovyScript serializableResourceMatchScript; - - @CheckForNull - private transient SecureGroovyScript resourceMatchScript; - - public LockableResourcesStruct(RequiredResourcesProperty property, - EnvVars env) { - required = new ArrayList<>(); - for (String name : property.getResources()) { - LockableResource r = LockableResourcesManager.get().fromName( - env.expand(name)); - if (r != null) { - this.required.add(r); - } - } - - label = env.expand(property.getLabelName()); - if (label == null) - label = ""; - - resourceMatchScript = property.getResourceMatchScript(); - serializableResourceMatchScript = new SerializableSecureGroovyScript(resourceMatchScript); - - requiredVar = property.getResourceNamesVar(); - - requiredNumber = property.getResourceNumber(); - if (requiredNumber != null && requiredNumber.equals("0")) - requiredNumber = null; - } - - /** - * Light-weight constructor for declaring a resource only. - * @param resources Resources to be required - */ - public LockableResourcesStruct(@Nullable List resources) { - this(resources, null, 0); - } - - public LockableResourcesStruct(@Nullable List resources, @Nullable String label, int quantity, String variable) { - this(resources, label, quantity); - requiredVar = variable; - } - - public LockableResourcesStruct(@Nullable List resources, @Nullable String label, int quantity) { - required = new ArrayList<>(); - if (resources != null) { - for (String resource : resources) { - LockableResource r = LockableResourcesManager.get().fromName(resource); - if (r != null) { - this.required.add(r); - } - } - } - - this.label = label; - if (this.label == null) { - this.label = ""; - } - - this.requiredNumber = null; - if (quantity > 0) { - this.requiredNumber = String.valueOf(quantity); - } - - // We do not support - this.serializableResourceMatchScript = null; - this.resourceMatchScript = null; - } - - /** - * Gets a system Groovy script to be executed in order to determine if the {@link LockableResource} matches the condition. - * @return System Groovy Script if defined - * @since TODO - * @see LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, java.util.Map) - */ - @CheckForNull - public SecureGroovyScript getResourceMatchScript() { - if (resourceMatchScript == null && serializableResourceMatchScript != null) { - resourceMatchScript = serializableResourceMatchScript.rehydrate(); - } - return resourceMatchScript; - } - - public String toString() { - return "Required resources: " + this.required + - ", Required label: " + this.label + - ", Required label script: " + (this.resourceMatchScript != null ? this.resourceMatchScript.getScript() : "") + - ", Variable name: " + this.requiredVar + - ", Number of resources: " + this.requiredNumber; - } - - private static final long serialVersionUID = 1L; + public List required; + public String label; + public String requiredVar; + public String requiredNumber; + + @CheckForNull private final SerializableSecureGroovyScript serializableResourceMatchScript; + + @CheckForNull private transient SecureGroovyScript resourceMatchScript; + + public LockableResourcesStruct(RequiredResourcesProperty property, EnvVars env) { + required = new ArrayList<>(); + for (String name : property.getResources()) { + LockableResource r = LockableResourcesManager.get().fromName(env.expand(name)); + if (r != null) { + this.required.add(r); + } + } + + label = env.expand(property.getLabelName()); + if (label == null) label = ""; + + resourceMatchScript = property.getResourceMatchScript(); + serializableResourceMatchScript = new SerializableSecureGroovyScript(resourceMatchScript); + + requiredVar = property.getResourceNamesVar(); + + requiredNumber = property.getResourceNumber(); + if (requiredNumber != null && requiredNumber.equals("0")) requiredNumber = null; + } + + /** + * Light-weight constructor for declaring a resource only. + * + * @param resources Resources to be required + */ + public LockableResourcesStruct(@Nullable List resources) { + this(resources, null, 0); + } + + public LockableResourcesStruct( + @Nullable List resources, @Nullable String label, int quantity, String variable) { + this(resources, label, quantity); + requiredVar = variable; + } + + public LockableResourcesStruct( + @Nullable List resources, @Nullable String label, int quantity) { + required = new ArrayList<>(); + if (resources != null) { + for (String resource : resources) { + LockableResource r = LockableResourcesManager.get().fromName(resource); + if (r != null) { + this.required.add(r); + } + } + } + + this.label = label; + if (this.label == null) { + this.label = ""; + } + + this.requiredNumber = null; + if (quantity > 0) { + this.requiredNumber = String.valueOf(quantity); + } + + // We do not support + this.serializableResourceMatchScript = null; + this.resourceMatchScript = null; + } + + /** + * Gets a system Groovy script to be executed in order to determine if the {@link + * LockableResource} matches the condition. + * + * @return System Groovy Script if defined + * @since TODO + * @see + * LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, + * java.util.Map) + */ + @CheckForNull + public SecureGroovyScript getResourceMatchScript() { + if (resourceMatchScript == null && serializableResourceMatchScript != null) { + resourceMatchScript = serializableResourceMatchScript.rehydrate(); + } + return resourceMatchScript; + } + + public String toString() { + return "Required resources: " + + this.required + + ", Required label: " + + this.label + + ", Required label script: " + + (this.resourceMatchScript != null ? this.resourceMatchScript.getScript() : "") + + ", Variable name: " + + this.requiredVar + + ", Number of resources: " + + this.requiredNumber; + } + + private static final long serialVersionUID = 1L; } From 9a83154bd069ecf770ff9aeda0c0eb68f471db20 Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Fri, 5 Jul 2019 10:11:40 +0300 Subject: [PATCH 0018/1078] Fix autocreate lock for free-style project --- .../queue/LockableResourcesStruct.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index 08e8b8a27..05baa3940 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -33,11 +33,16 @@ public class LockableResourcesStruct implements Serializable { public LockableResourcesStruct(RequiredResourcesProperty property, EnvVars env) { required = new ArrayList<>(); + + LockableResourcesManager resourcesManager = LockableResourcesManager.get(); for (String name : property.getResources()) { - LockableResource r = LockableResourcesManager.get().fromName(env.expand(name)); - if (r != null) { - this.required.add(r); + String resourceName = env.expand(name); + if (resourceName == null) { + continue; } + resourcesManager.createResource(resourceName); + LockableResource r = resourcesManager.fromName(resourceName); + this.required.add(r); } label = env.expand(property.getLabelName()); @@ -99,10 +104,10 @@ public LockableResourcesStruct( * LockableResource} matches the condition. * * @return System Groovy Script if defined - * @since TODO * @see * LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, * java.util.Map) + * @since TODO */ @CheckForNull public SecureGroovyScript getResourceMatchScript() { From 21d0f00b6858cf208f2bc4b8814003c31320ee50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ltje?= Date: Thu, 11 Jul 2019 17:36:12 -0400 Subject: [PATCH 0019/1078] don't save if nothing changes (#133) --- .../plugins/lockableresources/LockableResourcesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 84f52364e..0950f8bea 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -322,8 +322,8 @@ public synchronized boolean lock(Set resources, } LockStepExecution.proceed(resourceNames, context, logmessage, variable, inversePrecedence); } + save(); } - save(); return !needToWait; } From 15f5d1b1534174e3f08e0c9b55821c5125d6b1bc Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Thu, 4 Jul 2019 17:15:49 +0300 Subject: [PATCH 0020/1078] Create implicit locks as ephemeral --- .../lockableresources/LockableResource.java | 11 ++++++++++ .../LockableResourcesManager.java | 21 +++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 58f1816ab..468bc2b45 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -59,6 +59,7 @@ public class LockableResource extends AbstractDescribableImpl private String description = ""; private String labels = ""; private String reservedBy = null; + private boolean ephemeral; private long queueItemId = NOT_QUEUED; private String queueItemProject = null; @@ -126,6 +127,16 @@ public String getLabels() { return labels; } + @DataBoundSetter + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; + } + + @Exported + public boolean isEphemeral() { + return ephemeral; + } + public boolean isValidLabel(String candidate, Map params) { return labelsContain(candidate); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 0950f8bea..5f9a84bec 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -329,12 +329,23 @@ public synchronized boolean lock(Set resources, private synchronized void freeResources(List unlockResourceNames, @Nullable Run build) { for (String unlockResourceName : unlockResourceNames) { - for (LockableResource resource : this.resources) { - if (resource != null && resource.getName() != null && resource.getName().equals(unlockResourceName)) { - if (build == null || (resource.getBuild() != null && build.getExternalizableId().equals(resource.getBuild().getExternalizableId()))) { + Iterator resourceIterator = this.resources.iterator(); + while (resourceIterator.hasNext()) { + LockableResource resource = resourceIterator.next(); + if (resource != null + && resource.getName() != null + && resource.getName().equals(unlockResourceName)) { + if (build == null + || (resource.getBuild() != null + && build + .getExternalizableId() + .equals(resource.getBuild().getExternalizableId()))) { // No more contexts, unlock resource resource.unqueue(); resource.setBuild(null); + if (resource.isEphemeral()) { + resourceIterator.remove(); + } } } } @@ -493,7 +504,9 @@ public synchronized boolean createResource(String name) { if (name != null) { LockableResource existent = fromName(name); if (existent == null) { - getResources().add(new LockableResource(name)); + LockableResource resource = new LockableResource(name); + resource.setEphemeral(true); + getResources().add(resource); save(); return true; } From 156f7a1cf687dc564ee5dde710dc711a51a9978a Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Thu, 4 Jul 2019 18:20:51 +0300 Subject: [PATCH 0021/1078] Show `isEphemeral` flag in `Lockable Resources` page --- .../actions/LockableResourcesRootAction/index.jelly | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 5342ed767..bf63dba59 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -29,6 +29,7 @@ Resource Status Labels + Ephemeral Action @@ -49,6 +50,7 @@ ${resource.labels} + ${resource.ephemeral} @@ -63,6 +65,7 @@ ${resource.reservedBy} ${resource.labels} + ${resource.ephemeral} ${resource.labels} + ${resource.ephemeral} @@ -89,6 +93,7 @@ FREE ${resource.labels} + ${resource.ephemeral} From 5d85ff8ad15cc236dbd1653956acfcefa2b5d4fa Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Thu, 4 Jul 2019 18:59:05 +0300 Subject: [PATCH 0022/1078] Hide ephemeral locks in `Manage Jenkins` > `Configure System page` --- .../LockableResourcesManager.java | 15 +++++++++++++++ .../LockableResourcesManager/config.jelly | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 5f9a84bec..06690228d 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.io.PrintStream; +import java.util.concurrent.ExecutionException; import java.util.HashSet; import java.util.Iterator; import java.util.Map; @@ -68,6 +69,20 @@ public List getResources() { return resources; } + public List getDeclaredResources() { + ArrayList declaredResources = new ArrayList<>(); + for (LockableResource r : resources) { + if (!r.isEphemeral()) { + declaredResources.add(r); + } + } + return declaredResources; + } + + public void setDeclaredResources(List resources) { + this.resources = resources; + } + public List getResourcesFromProject(String fullName) { List matching = new ArrayList<>(); for (LockableResource r : resources) { diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config.jelly index 658b7595f..03e70640e 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config.jelly @@ -13,7 +13,7 @@ xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> - + From c9e491cac8e60a931d58de78efd70c65322acafa Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Thu, 4 Jul 2019 22:38:14 +0300 Subject: [PATCH 0023/1078] Merge locks list on apply configuration --- .../LockableResourcesManager.java | 61 ++++++++++++------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 06690228d..c9b5c0d2b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -15,14 +15,8 @@ import java.io.IOException; import java.io.PrintStream; +import java.util.*; import java.util.concurrent.ExecutionException; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -41,7 +35,6 @@ import org.kohsuke.stapler.StaplerRequest; import edu.umd.cs.findbugs.annotations.Nullable; -import java.util.concurrent.ExecutionException; import javax.annotation.Nonnull; @Extension @@ -69,7 +62,7 @@ public List getResources() { return resources; } - public List getDeclaredResources() { + public synchronized List getDeclaredResources() { ArrayList declaredResources = new ArrayList<>(); for (LockableResource r : resources) { if (!r.isEphemeral()) { @@ -79,8 +72,41 @@ public List getDeclaredResources() { return declaredResources; } - public void setDeclaredResources(List resources) { - this.resources = resources; + public synchronized void setDeclaredResources(List declaredResources) { + Map lockedResources = new HashMap<>(); + for (LockableResource r : this.resources) { + if (!r.isLocked()) continue; + lockedResources.put(r.getName(), r); + } + + // Removed from configuration locks became ephemeral. + ArrayList mergedResources = new ArrayList<>(); + Set addedLocks = new HashSet<>(); + for (LockableResource r : declaredResources) { + if (!addedLocks.add(r.getName())) { + continue; + } + LockableResource locked = lockedResources.remove(r.getName()); + if (locked != null) { + // Merge already locked lock. + locked.setDescription(r.getDescription()); + locked.setLabels(r.getLabels()); + locked.setEphemeral(false); + mergedResources.add(locked); + continue; + } + mergedResources.add(r); + } + + for (LockableResource r : lockedResources.values()) { + // Removed locks became ephemeral. + r.setDescription(""); + r.setLabels(""); + r.setEphemeral(true); + mergedResources.add(r); + } + + this.resources = mergedResources; } public List getResourcesFromProject(String fullName) { @@ -655,16 +681,9 @@ public synchronized void reset(List resources) { public boolean configure(StaplerRequest req, JSONObject json) throws FormException { try { - List newResouces = req.bindJSONToList( - LockableResource.class, json.get("resources")); - for (LockableResource r : newResouces) { - LockableResource old = fromName(r.getName()); - if (old != null) { - r.setBuild(old.getBuild()); - r.setQueued(r.getQueueItemId(), r.getQueueItemProject()); - } - } - resources = newResouces; + List newResouces = + req.bindJSONToList(LockableResource.class, json.get("declaredResources")); + setDeclaredResources(newResouces); save(); return true; } catch (JSONException e) { From 7eaf7cc2b3f8848a71262fce373b873ed6ae90a4 Mon Sep 17 00:00:00 2001 From: "Artem V. Navrotskiy" Date: Fri, 5 Jul 2019 12:47:58 +0300 Subject: [PATCH 0024/1078] Add check for lock resource [not]present in some tests --- .../lockableresources/LockStepTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 443055c8f..e78c626f2 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -1,6 +1,7 @@ package org.jenkins.plugins.lockableresources; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; @@ -37,6 +38,8 @@ public void autoCreateResource() throws Exception { j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); j.assertLogContains("Resource [resource1] did not exist. Created.", b1); + + assertNull(LockableResourcesManager.get().fromName("resource1")); } @Test @@ -58,6 +61,9 @@ public void autoCreateResourceFreeStyle() throws IOException, InterruptedExcepti } j.waitForMessage("acquired lock on [resource1]", fb1); + j.waitForCompletion(fb1); + + assertNull(LockableResourcesManager.get().fromName("resource1")); } @Test @@ -76,6 +82,8 @@ public void lockWithLabel() throws Exception { j.assertLogContains("Lock released on resource [Label: label1]", b1); j.assertLogContains("Resource locked: resource1", b1); isPaused(b1, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); } @Test @@ -118,6 +126,10 @@ public void lockOrderLabel() throws Exception { SemaphoreStep.success("wait-inside/3", null); j.waitForMessage("Finish", b3); isPaused(b3, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); + assertNotNull(LockableResourcesManager.get().fromName("resource2")); + assertNotNull(LockableResourcesManager.get().fromName("resource3")); } @Test @@ -166,6 +178,10 @@ public void lockOrderLabelQuantity() throws Exception { SemaphoreStep.success("wait-inside/2", null); j.waitForMessage("Finish", b2); isPaused(b2, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); + assertNotNull(LockableResourcesManager.get().fromName("resource2")); + assertNotNull(LockableResourcesManager.get().fromName("resource3")); } @Test @@ -220,6 +236,10 @@ public void lockOrderLabelQuantityFreedResources() throws Exception { j.waitForMessage("Finish", b3); isPaused(b2, 1, 0); isPaused(b3, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); + assertNotNull(LockableResourcesManager.get().fromName("resource2")); + assertNotNull(LockableResourcesManager.get().fromName("resource3")); } @Test @@ -324,6 +344,8 @@ public void parallelLock() throws Exception { j.waitForMessage("[a] Lock acquired on [resource1]", b1); isPaused(b1, 2, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); } @Test @@ -721,6 +743,10 @@ public void lockWithLabelAndLabeledResource() throws Exception { SemaphoreStep.success("wait-inside-p3/1", null); j.waitForMessage("Finish", b3); isPaused(b3, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); + assertNotNull(LockableResourcesManager.get().fromName("resource2")); + assertNotNull(LockableResourcesManager.get().fromName("resource3")); } @Test @@ -791,5 +817,10 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { // Could be any 3 resources, so just check the beginning of the message j.assertLogContains("Resources locked: [resource", b2); isPaused(b2, 1, 0); + + assertNotNull(LockableResourcesManager.get().fromName("resource1")); + assertNotNull(LockableResourcesManager.get().fromName("resource2")); + assertNotNull(LockableResourcesManager.get().fromName("resource3")); + assertNotNull(LockableResourcesManager.get().fromName("resource4")); } } From 2da32c8d200668db5047400f247a184b8e71e5bc Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Mon, 22 Jul 2019 19:44:39 +0200 Subject: [PATCH 0025/1078] Extend reserveOverRestart test with a freestyle job --- .../LockStepWithRestartTest.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 6d1d78dc7..1bd7ef14f 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -128,8 +128,7 @@ public void testReserveOverRestart() { (JenkinsRule j) -> { LockableResourcesManager manager = LockableResourcesManager.get(); manager.createResource("resource1"); - manager.fromName("resource1").setReservedBy("user"); - manager.save(); + manager.reserve(Collections.singletonList(manager.fromName("resource1")), "user"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( @@ -138,11 +137,22 @@ public void testReserveOverRestart() { WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked, waiting...", b1); isPaused(b1, 1, 1); + + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + + f.scheduleBuild2(0); + + while (j.jenkins.getQueue().getItems().length != 1) { + System.out.println("Waiting for freestyle to be queued..."); + Thread.sleep(1000); + } }); story.then( (JenkinsRule j) -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); + FreeStyleProject f = j.jenkins.getItemByFullName("f", FreeStyleProject.class); WorkflowRun b1 = p.getBuildByNumber(1); LockableResourcesManager manager = LockableResourcesManager.get(); @@ -153,6 +163,8 @@ public void testReserveOverRestart() { isPaused(b1, 1, 0); j.waitForMessage("Finish", b1); isPaused(b1, 1, 0); + + j.waitUntilNoActivity(); }); } } From 8721490711d927d23a8fdcbfb679ac13294b4841 Mon Sep 17 00:00:00 2001 From: cashlalala Date: Wed, 24 Jul 2019 02:51:45 +0800 Subject: [PATCH 0026/1078] add the permission control of viewing lockable resources (#77) --- .../actions/LockableResourcesRootAction.java | 14 +++++++------- .../plugins/lockableresources/Messages.properties | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index aaa20661b..f7f460d76 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -45,15 +45,15 @@ public class LockableResourcesRootAction implements RootAction { Messages._LockableResourcesRootAction_ReservePermission_Description(), Jenkins.ADMINISTER, PermissionScope.JENKINS); + public static final Permission VIEW = new Permission(PERMISSIONS_GROUP, + Messages.LockableResourcesRootAction_ViewPermission(), + Messages._LockableResourcesRootAction_ViewPermission_Description(), Jenkins.ADMINISTER, + PermissionScope.JENKINS); + public static final String ICON = "/plugin/lockable-resources/img/device-24x24.png"; public String getIconFileName() { - if (User.current() != null) { - // only show if logged in - return ICON; - } else { - return null; - } + return (Jenkins.getInstance().hasPermission(VIEW)) ? ICON : null; } public String getUserName() { @@ -69,7 +69,7 @@ public String getDisplayName() { } public String getUrlName() { - return "lockable-resources"; + return (Jenkins.getInstance().hasPermission(VIEW)) ? "lockable-resources" : ""; } public List getResources() { diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties index f634f92cb..d17aeccf9 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties @@ -14,3 +14,7 @@ LockableResourcesRootAction.UnlockPermission.Description=This permission grants LockableResourcesRootAction.ReservePermission=Reserve LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually \ reserve lockable resources outside of a build. +LockableResourcesRootAction.ViewPermission=View +LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view \ + lockable resources. + From 1dc46407856f4de8e30749c19d475719ab45a882 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Wed, 24 Jul 2019 01:06:01 +0200 Subject: [PATCH 0027/1078] Update parent to 3.47 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ba2ee053..fe21627a6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.43 + 3.47 From 5b2fb16b984d2f80010f63ea00953d934e9170ec Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Wed, 24 Jul 2019 01:09:16 +0200 Subject: [PATCH 0028/1078] Add configuration for release drafter --- .github/release-drafter.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 000000000..155554f31 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,2 @@ +_extends: .github +tag-template: lockable-resources-$NEXT_MINOR_VERSION From 8c8ce1181379bfe9e097dec18fd41df69f0fb303 Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Sat, 24 Aug 2019 16:45:28 +0200 Subject: [PATCH 0029/1078] add blocking build to log --- .../plugins/lockableresources/LockStepExecution.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 9a100c873..d30fbd461 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -65,7 +65,16 @@ public boolean start() throws Exception { // determine if there are enough resources available to proceed Set available = LockableResourcesManager.get().checkResourcesAvailability(resourceHolderList, listener.getLogger(), null); if (available == null || !LockableResourcesManager.get().lock(available, run, getContext(), step.toString(), step.variable, step.inversePrecedence)) { - listener.getLogger().println("[" + step + "] is locked, waiting..."); + // if the resource is known, we could output the active/blocking job/build + LockableResource resource = LockableResourcesManager.get().fromName(step.resource); + if (resource != null && resource.getBuildName() != null) { + listener + .getLogger() + .println("[" + step + "] is locked by " + resource.getBuildName() + ", waiting..."); + + } else { + listener.getLogger().println("[" + step + "] is locked, waiting..."); + } LockableResourcesManager.get().queueContext(getContext(), resourceHolderList, step.toString()); } // proceed is called inside lock if execution is possible return false; From 996570bafe6111388ce4c7bb5896d99f484da4c5 Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Mon, 26 Aug 2019 21:59:44 +0200 Subject: [PATCH 0030/1078] adjust tests for mentioning blocking build --- .../LockStepHardKillTest.java | 6 ++-- .../lockableresources/LockStepTest.java | 30 +++++++++---------- .../LockStepWithRestartTest.java | 6 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index 150cdfa85..02dc915c8 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -35,7 +35,7 @@ public void hardKillNewBuildClearsLock() throws Exception { WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); // Make sure that b2 is blocked on b1's lock. - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the @@ -44,7 +44,7 @@ public void hardKillNewBuildClearsLock() throws Exception { p3.setDefinition( new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked, waiting...", b3); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); // Kill b1 hard. @@ -86,7 +86,7 @@ public void hardKillWithWaitingRuns() throws Exception { for (int i = 0; i < 3; i++) { WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); if (prevBuild != null) { - j.waitForMessage("[resource1] is locked, waiting...", rNext); + j.waitForMessage("[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); interruptTermKill(prevBuild); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index e78c626f2..296a0c9ee 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -254,12 +254,12 @@ public void lockOrder() throws Exception { WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); // Ensure that b2 reaches the lock before b3 - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); // Both 2 and 3 are waiting for locking resource1 - j.waitForMessage("[resource1] is locked, waiting...", b3); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); // Unlock resource1 @@ -292,12 +292,12 @@ public void lockInverseOrder() throws Exception { WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); // Ensure that b2 reaches the lock before b3 - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); // Both 2 and 3 are waiting for locking resource1 - j.waitForMessage("[resource1] is locked, waiting...", b3); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); // Unlock resource1 @@ -337,7 +337,7 @@ public void parallelLock() throws Exception { // both messages are in the log because branch b acquired the lock and branch a is waiting to // lock j.waitForMessage("[b] Lock acquired on [resource1]", b1); - j.waitForMessage("[a] [resource1] is locked, waiting...", b1); + j.waitForMessage("[a] [resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); isPaused(b1, 2, 1); SemaphoreStep.success("wait-b/1", null); @@ -372,10 +372,10 @@ public boolean perform( } }); semaphore.acquire(); - f.scheduleBuild2(0).waitForStart(); + FreeStyleBuild f1 = f.scheduleBuild2(0).waitForStart(); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked, waiting...", b1); + j.waitForMessage("[resource1] is locked by " + f1.getFullDisplayName() + ", waiting...", b1); isPaused(b1, 1, 1); semaphore.release(); @@ -413,9 +413,9 @@ public void deleteRunningBuildNewBuildClearsLock() throws Exception { WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); // Make sure that b2 is blocked on b1's lock. - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); - j.waitForMessage("[resource1] is locked, waiting...", b3); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); b1.delete(); @@ -454,7 +454,7 @@ public void unlockButtonWithWaitingRuns() throws Exception { for (int i = 0; i < 3; i++) { WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); if (prevBuild != null) { - j.waitForMessage("[resource1] is locked, waiting...", rNext); + j.waitForMessage("[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); wc.goTo("lockable-resources/unlock?resource=resource1"); } @@ -496,7 +496,7 @@ public void parallelLockRelease() throws Exception { for (int i = 0; i < 5; i++) { WorkflowRun rNext = job.scheduleBuild2(0).waitForStart(); if (toUnlock != null) { - j.waitForMessage("[resource1] is locked, waiting...", rNext); + j.waitForMessage("[resource1] is locked by " + toUnlock.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); SemaphoreStep.success("wait-inside-1/" + i, null); } @@ -616,7 +616,7 @@ public void lockMultipleResources() throws Exception { new CpsFlowDefinition( "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); @@ -624,7 +624,7 @@ public void lockMultipleResources() throws Exception { new CpsFlowDefinition( "lock('resource2') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'")); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource2] is locked, waiting...", b3); + j.waitForMessage("[resource2] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); // Unlock resources @@ -664,7 +664,7 @@ public void lockWithLabelAndResource() throws Exception { new CpsFlowDefinition( "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); @@ -715,7 +715,7 @@ public void lockWithLabelAndLabeledResource() throws Exception { new CpsFlowDefinition( "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 1bd7ef14f..bae553521 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -41,12 +41,12 @@ public void lockOrderRestart() { SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); // Ensure that b2 reaches the lock before b3 - j.waitForMessage("[resource1] is locked, waiting...", b2); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); // Both 2 and 3 are waiting for locking resource1 - j.waitForMessage("[resource1] is locked, waiting...", b3); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); }); @@ -64,7 +64,7 @@ public void lockOrderRestart() { j.waitForMessage("Lock acquired on [resource1]", b2); isPaused(b2, 1, 0); - j.assertLogContains("[resource1] is locked, waiting...", b3); + j.assertLogContains("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); SemaphoreStep.success("wait-inside/2", null); SemaphoreStep.waitForStart("wait-inside/3", b3); From 175f23bddd6483ac060a2aacb16b4f44db09bce1 Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Mon, 26 Aug 2019 22:02:32 +0200 Subject: [PATCH 0031/1078] format changed file --- .../lockableresources/LockStepExecution.java | 259 ++++++++++-------- 1 file changed, 146 insertions(+), 113 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index d30fbd461..e136ecee5 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -1,12 +1,16 @@ package org.jenkins.plugins.lockableresources; +import com.google.common.base.Joiner; +import com.google.inject.Inject; +import hudson.EnvVars; +import hudson.model.Run; +import hudson.model.TaskListener; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; - import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; @@ -15,56 +19,57 @@ import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkinsci.plugins.workflow.steps.StepContextParameter; - -import com.google.common.base.Joiner; -import com.google.inject.Inject; - -import hudson.EnvVars; -import hudson.model.Run; -import hudson.model.TaskListener; import org.jenkinsci.plugins.workflow.support.actions.PauseAction; public class LockStepExecution extends AbstractStepExecutionImpl { - private static final Joiner COMMA_JOINER = Joiner.on(','); - - @Inject(optional = true) - private LockStep step; + private static final Joiner COMMA_JOINER = Joiner.on(','); - @StepContextParameter - private transient Run run; + @Inject(optional = true) + private LockStep step; - @StepContextParameter - private transient TaskListener listener; + @StepContextParameter private transient Run run; - @StepContextParameter - private transient FlowNode node; + @StepContextParameter private transient TaskListener listener; - private static final Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); + @StepContextParameter private transient FlowNode node; - @Override - public boolean start() throws Exception { - step.validate(); + private static final Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); - node.addAction(new PauseAction("Lock")); - listener.getLogger().println("Trying to acquire lock on [" + step + "]"); + @Override + public boolean start() throws Exception { + step.validate(); - List resourceHolderList = new ArrayList<>(); + node.addAction(new PauseAction("Lock")); + listener.getLogger().println("Trying to acquire lock on [" + step + "]"); - for (LockStepResource resource : step.getResources()) { - List resources = new ArrayList<>(); - if (resource.resource != null) { - if (LockableResourcesManager.get().createResource(resource.resource)) { - listener.getLogger().println("Resource [" + resource + "] did not exist. Created."); - } - resources.add(resource.resource); - } - resourceHolderList.add(new LockableResourcesStruct(resources, resource.label, resource.quantity)); - } + List resourceHolderList = new ArrayList<>(); - // determine if there are enough resources available to proceed - Set available = LockableResourcesManager.get().checkResourcesAvailability(resourceHolderList, listener.getLogger(), null); - if (available == null || !LockableResourcesManager.get().lock(available, run, getContext(), step.toString(), step.variable, step.inversePrecedence)) { + for (LockStepResource resource : step.getResources()) { + List resources = new ArrayList<>(); + if (resource.resource != null) { + if (LockableResourcesManager.get().createResource(resource.resource)) { + listener.getLogger().println("Resource [" + resource + "] did not exist. Created."); + } + resources.add(resource.resource); + } + resourceHolderList.add( + new LockableResourcesStruct(resources, resource.label, resource.quantity)); + } + + // determine if there are enough resources available to proceed + Set available = + LockableResourcesManager.get() + .checkResourcesAvailability(resourceHolderList, listener.getLogger(), null); + if (available == null + || !LockableResourcesManager.get() + .lock( + available, + run, + getContext(), + step.toString(), + step.variable, + step.inversePrecedence)) { // if the resource is known, we could output the active/blocking job/build LockableResource resource = LockableResourcesManager.get().fromName(step.resource); if (resource != null && resource.getBuildName() != null) { @@ -75,79 +80,107 @@ public boolean start() throws Exception { } else { listener.getLogger().println("[" + step + "] is locked, waiting..."); } - LockableResourcesManager.get().queueContext(getContext(), resourceHolderList, step.toString()); - } // proceed is called inside lock if execution is possible - return false; - } - - public static void proceed(final List resourcenames, StepContext context, String resourceDescription, final String variable, boolean inversePrecedence) { - Run r = null; - FlowNode node = null; - try { - r = context.get(Run.class); - node = context.get(FlowNode.class); - context.get(TaskListener.class).getLogger().println("Lock acquired on [" + resourceDescription + "]"); - } catch (Exception e) { - context.onFailure(e); - return; - } - - LOGGER.finest("Lock acquired on [" + resourceDescription + "] by " + r.getExternalizableId()); - try { - PauseAction.endCurrentPause(node); - BodyInvoker bodyInvoker = context.newBodyInvoker(). - withCallback(new Callback(resourcenames, resourceDescription, variable, inversePrecedence)); - if(variable != null && variable.length()>0) - // set the variable for the duration of the block - bodyInvoker.withContext(EnvironmentExpander.merge(context.get(EnvironmentExpander.class), new EnvironmentExpander() { - @Override - public void expand(EnvVars env) throws IOException, InterruptedException { - final String resources = COMMA_JOINER.join(resourcenames); - LOGGER.finest("Setting [" + variable + "] to [" + resources - + "] for the duration of the block"); - - env.override(variable, resources); - } - })); - bodyInvoker.start(); - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - } - - private static final class Callback extends BodyExecutionCallback.TailCall { - - private final List resourceNames; - private final String resourceDescription; - private final String variable; - private final boolean inversePrecedence; - - Callback(List resourceNames, String resourceDescription, String variable, boolean inversePrecedence) { - this.resourceNames = resourceNames; - this.resourceDescription = resourceDescription; - this.variable = variable; - this.inversePrecedence = inversePrecedence; - } - - protected void finished(StepContext context) throws Exception { - LockableResourcesManager.get().unlockNames(this.resourceNames, context.get(Run.class), this.variable, this.inversePrecedence); - context.get(TaskListener.class).getLogger().println("Lock released on resource [" + resourceDescription + "]"); - LOGGER.finest("Lock released on [" + resourceDescription + "]"); - } - - private static final long serialVersionUID = 1L; - - } - - @Override - public void stop(Throwable cause) throws Exception { - boolean cleaned = LockableResourcesManager.get().unqueueContext(getContext()); - if (!cleaned) { - LOGGER.log(Level.WARNING, "Cannot remove context from lockable resource witing list. The context is not in the waiting list."); - } - getContext().onFailure(cause); - } - - private static final long serialVersionUID = 1L; - + LockableResourcesManager.get() + .queueContext(getContext(), resourceHolderList, step.toString()); + } // proceed is called inside lock if execution is possible + return false; + } + + public static void proceed( + final List resourcenames, + StepContext context, + String resourceDescription, + final String variable, + boolean inversePrecedence) { + Run r = null; + FlowNode node = null; + try { + r = context.get(Run.class); + node = context.get(FlowNode.class); + context + .get(TaskListener.class) + .getLogger() + .println("Lock acquired on [" + resourceDescription + "]"); + } catch (Exception e) { + context.onFailure(e); + return; + } + + LOGGER.finest("Lock acquired on [" + resourceDescription + "] by " + r.getExternalizableId()); + try { + PauseAction.endCurrentPause(node); + BodyInvoker bodyInvoker = + context + .newBodyInvoker() + .withCallback( + new Callback(resourcenames, resourceDescription, variable, inversePrecedence)); + if (variable != null && variable.length() > 0) + // set the variable for the duration of the block + bodyInvoker.withContext( + EnvironmentExpander.merge( + context.get(EnvironmentExpander.class), + new EnvironmentExpander() { + @Override + public void expand(EnvVars env) throws IOException, InterruptedException { + final String resources = COMMA_JOINER.join(resourcenames); + LOGGER.finest( + "Setting [" + + variable + + "] to [" + + resources + + "] for the duration of the block"); + + env.override(variable, resources); + } + })); + bodyInvoker.start(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + private static final class Callback extends BodyExecutionCallback.TailCall { + + private final List resourceNames; + private final String resourceDescription; + private final String variable; + private final boolean inversePrecedence; + + Callback( + List resourceNames, + String resourceDescription, + String variable, + boolean inversePrecedence) { + this.resourceNames = resourceNames; + this.resourceDescription = resourceDescription; + this.variable = variable; + this.inversePrecedence = inversePrecedence; + } + + protected void finished(StepContext context) throws Exception { + LockableResourcesManager.get() + .unlockNames( + this.resourceNames, context.get(Run.class), this.variable, this.inversePrecedence); + context + .get(TaskListener.class) + .getLogger() + .println("Lock released on resource [" + resourceDescription + "]"); + LOGGER.finest("Lock released on [" + resourceDescription + "]"); + } + + private static final long serialVersionUID = 1L; + } + + @Override + public void stop(Throwable cause) throws Exception { + boolean cleaned = LockableResourcesManager.get().unqueueContext(getContext()); + if (!cleaned) { + LOGGER.log( + Level.WARNING, + "Cannot remove context from lockable resource witing list. The context is not in the waiting list."); + } + getContext().onFailure(cause); + } + + private static final long serialVersionUID = 1L; } From a95727da6ba7b3fc0862d76828104d6728f5f542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 24 Jul 2018 11:09:03 +0200 Subject: [PATCH 0032/1078] Check that a label is valid before waiting on it --- .../plugins/lockableresources/LockStepResource.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java index 428f73a5c..be3164e7e 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java @@ -78,11 +78,15 @@ public void validate() throws Exception { /** * Label and resource are mutual exclusive. + * The label, if provided, must be configured (at least one resource must have this label). */ public static void validate(String resource, String label, int quantity) throws Exception { if (label != null && !label.isEmpty() && resource != null && !resource.isEmpty()) { throw new IllegalArgumentException("Label and resource name cannot be specified simultaneously."); } + if (label != null && !LockableResourcesManager.get().isValidLabel( label ) ) { + throw new IllegalArgumentException("The label does not exist: " + label); + } } private static final long serialVersionUID = 1L; @@ -108,6 +112,9 @@ public static FormValidation doCheckLabel(@QueryParameter String value, @QueryPa if ((resourceLabel == null) && (resourceName == null)) { return FormValidation.error("Either label or resource name must be specified."); } + if (resourceLabel != null && !LockableResourcesManager.get().isValidLabel(resourceLabel)) { + return FormValidation.error("The label does not exist: " + resourceLabel); + } return FormValidation.ok(); } From 3b90b050d623cbfc2e8cdbf584b2af054fe51b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 24 Jul 2018 11:09:43 +0200 Subject: [PATCH 0033/1078] Test locking on an invalid label --- .../plugins/lockableresources/LockStepTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index e78c626f2..7981df1ec 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -823,4 +823,21 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { assertNotNull(LockableResourcesManager.get().fromName("resource3")); assertNotNull(LockableResourcesManager.get().fromName("resource4")); } + + @Test + public void lockWithInvalidLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'invalidLabel', variable: 'var', quantity: 1) {\n" + + " echo \"Resource locked: ${env.var}\"\n" + + "}\n" + + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.FAILURE, b1); + j.assertLogContains("The label does not exist: invalidLabel", b1); + isPaused(b1, 0, 0); + } } From 1ecdd80fd88aeafc695b6ecff2c8ab4507ebc80d Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 07:20:33 +0200 Subject: [PATCH 0034/1078] Add documentation (mostly from the old wiki page) --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73fe82cf4..285b9e30f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,80 @@ # Jenkins Lockable Resources Plugin +[![Jenkins Plugin](https://img.shields.io/jenkins/plugin/v/lockable-resources.svg)](https://plugins.jenkins.io/lockable-resources) +[![GitHub release](https://img.shields.io/github/release/jenkinsci/lockable-resources-plugin.svg?label=release)](https://github.com/jenkinsci/lockable-resources-plugin/releases/latest) +[![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/lockable-resources.svg?color=blue)](https://plugins.jenkins.io/lockable-resources) [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) [![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) [![Maintenance](https://img.shields.io/maintenance/yes/2019.svg)]() -This plugins allows to define "lockable resources" in the global configuration. -These resources can then be "required" by jobs. If a job requires a resource -which is already locked, it will be put in queue until the resource is released. +This plugin allows defining lockable resources (such as printers, phones, +computers, etc.) that can be used by builds. If a build requires a resource +which is already locked, it will wait for the resource to be free. + +## Usage + +### Adding lockable resources + +1. In *Manage Jenkins* > *Configure System* go to **Lockable Resources + Manager** +2. Select *Add Lockable Resource* + +Each lockable resource has the following properties: + +- **Name** - A name (not containing spaces!) for this particular resource, i.e. + `DK_Printers` +- **Description** - A verbose description of this particular resource, + i.e. ` Printers in the Danish Office` +- **Labels** - Space-delimited list of Labels (Not containing spaces) used to + identify a pool of resources. i.e. `DK_Printers_Office`, + `DK_Printer_Production`, `DK_Printer_Engineering` +- **Reserved by** - If non-empty, the resource will be unavailable for jobs. + i.e. `All printers are currently not available due to maintenance.` + +### Using a resource in a freestyle job + +When configuring the job, select **This build requires lockable resources**. +Please see the help item for each field for details. + +### Using a resource in a pipeline job + +When the `lock` step is used in a Pipeline, if the resource to be locked isn't +already defined in the Jenkins global configuration, an ephermal resource is +used: These resources only exist as long as any running build is referencing +them. + +Examples: + +```groovy +echo 'Starting' +lock('my-resource-name') { + echo 'Do something here that requires unique access to the resource' + // any other build will wait until the one locking the resource leaves this block +} +echo 'Finish' +``` + +```groovy +lock(resource: 'staging-server', inversePrecedence: true) { + node { + servers.deploy 'staging' + } + input message: "Does ${jettyUrl}staging/ look good?" +} +``` + +```groovy +lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { + echo env.LOCKED_RESOURCE +} +``` + +## Changelog + +* See [GitHub Releases](https://github.com/jenkinsci/lockable-resources-plugin/releases) + for recent versions +* See the [plugin's Wiki page](https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin#LockableResourcesPlugin-Changelog) + for versions 2.5 and older ## Contributing From 8c19f35e1871dec7f391b26e3c197cfe8aa368bb Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 07:22:38 +0200 Subject: [PATCH 0035/1078] Use GitHub as source for plugins.jenkins.io --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe21627a6..5a0814e0e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ computers) that can be used by builds. If a build requires an external resource which is already locked, it will wait for the resource to be free. - https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin + https://github.com/jenkinsci/lockable-resources-plugin 2013 From 086c71d64c2b62a70dc1b4021deea122fc122c2b Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 13:48:59 +0200 Subject: [PATCH 0036/1078] Fix name to make intent clear Co-Authored-By: Feiko Nanninga --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 285b9e30f..5b811f799 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ which is already locked, it will wait for the resource to be free. Each lockable resource has the following properties: - **Name** - A name (not containing spaces!) for this particular resource, i.e. - `DK_Printers` + `DK_Printer_ColorA3_2342` - **Description** - A verbose description of this particular resource, i.e. ` Printers in the Danish Office` - **Labels** - Space-delimited list of Labels (Not containing spaces) used to From 417c1a0be64a63b38a2283bc30cbeb33393aad76 Mon Sep 17 00:00:00 2001 From: Bryan Date: Tue, 1 Oct 2019 22:31:52 +0200 Subject: [PATCH 0037/1078] JENKINS-55182 / jenkinsci#121: add support for configuration as code including unit tests (#146) --- README.md | 14 +++++ pom.xml | 14 +++++ .../LockableResourcesManager.java | 28 +++++---- .../ConfigurationAsCodeTest.java | 61 +++++++++++++++++++ .../casc_expected_output.yml | 5 ++ .../configuration-as-code.yml | 13 ++++ 6 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java create mode 100644 src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml create mode 100644 src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml diff --git a/README.md b/README.md index 5b811f799..dee2e3224 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,20 @@ lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { * See the [plugin's Wiki page](https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin#LockableResourcesPlugin-Changelog) for versions 2.5 and older +## Configuration as Code +This plugin can be configured via [Configuration-as-Code](https://github.com/jenkinsci/configuration-as-code-plugin). + +### Example configuration +``` +unclassified: + lockableResourcesManager: + declaredResources: + - name: "Resource_A" + description: "Description_A" + labels: "Label_A" + reservedBy: "Reserved_A" +``` + ## Contributing If you want to contribute to this plugin, you probably will need a Jenkins plugin developement diff --git a/pom.xml b/pom.xml index 5a0814e0e..5e1392e40 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ 8 2.12 2.60.3 + 1.25 1C @@ -119,6 +120,19 @@ 2.0 test + + io.jenkins + configuration-as-code + ${configuration-as-code.version} + test + + + io.jenkins + configuration-as-code + ${configuration-as-code.version} + tests + test + diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index c9b5c0d2b..7f4c36e7d 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -32,6 +32,7 @@ import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct; import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; import edu.umd.cs.findbugs.annotations.Nullable; @@ -72,6 +73,7 @@ public synchronized List getDeclaredResources() { return declaredResources; } + @DataBoundSetter public synchronized void setDeclaredResources(List declaredResources) { Map lockedResources = new HashMap<>(); for (LockableResource r : this.resources) { @@ -677,19 +679,19 @@ public synchronized void reset(List resources) { save(); } - @Override - public boolean configure(StaplerRequest req, JSONObject json) - throws FormException { - try { - List newResouces = - req.bindJSONToList(LockableResource.class, json.get("declaredResources")); - setDeclaredResources(newResouces); - save(); - return true; - } catch (JSONException e) { - return false; - } - } + @Override + public boolean configure(StaplerRequest req, JSONObject json) throws FormException { + BulkChange bc = new BulkChange(this); + try { + req.bindJSON(this, json); + bc.commit(); + } catch (IOException exception) { + LOGGER.log( + Level.WARNING, "Exception occurred while committing bulkchange operation.", exception); + return false; + } + return true; + } /** * Checks if there are enough resources available to satisfy the requirements specified diff --git a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java new file mode 100644 index 000000000..9f1c10e94 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java @@ -0,0 +1,61 @@ +package org.jenkins.plugins.lockableresources; + +import static io.jenkins.plugins.casc.misc.Util.*; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import io.jenkins.plugins.casc.ConfigurationContext; +import io.jenkins.plugins.casc.ConfiguratorRegistry; +import io.jenkins.plugins.casc.misc.ConfiguredWithCode; +import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; +import io.jenkins.plugins.casc.model.CNode; +import java.util.List; +import org.junit.ClassRule; +import org.junit.Test; + +public class ConfigurationAsCodeTest { + + @ClassRule + @ConfiguredWithCode("configuration-as-code.yml") + public static JenkinsConfiguredWithCodeRule r = new JenkinsConfiguredWithCodeRule(); + + @Test + public void should_support_configuration_as_code() throws Exception { + List declaredResources = + LockableResourcesManager.get().getDeclaredResources(); + assertEquals( + "The number of declared resources is wrong. Check your configuration-as-code.yml", + 1, + declaredResources.size()); + + LockableResource declaredResouce = declaredResources.get(0); + assertEquals("Resource_A", declaredResouce.getName()); + assertEquals("Description_A", declaredResouce.getDescription()); + assertEquals("Label_A", declaredResouce.getLabels()); + assertEquals("Reserved_A", declaredResouce.getReservedBy()); + + List resources = LockableResourcesManager.get().getResources(); + assertEquals( + "The number of resources is wrong. Check your configuration-as-code.yml", + 1, + resources.size()); + + LockableResource resource = resources.get(0); + assertEquals("Resource_A", resource.getName()); + assertEquals("Description_A", resource.getDescription()); + assertEquals("Label_A", resource.getLabels()); + assertEquals("Reserved_A", resource.getReservedBy()); + } + + @Test + public void should_support_configuration_export() throws Exception { + ConfiguratorRegistry registry = ConfiguratorRegistry.get(); + ConfigurationContext context = new ConfigurationContext(registry); + CNode yourAttribute = getUnclassifiedRoot(context).get("lockableResourcesManager"); + String exported = toYamlString(yourAttribute); + String expected = toStringFromYamlFile(this, "casc_expected_output.yml"); + + assertThat(exported, is(expected)); + } +} diff --git a/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml b/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml new file mode 100644 index 000000000..3572a0f8f --- /dev/null +++ b/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml @@ -0,0 +1,5 @@ +declaredResources: +- description: "Description_A" + labels: "Label_A" + name: "Resource_A" + reservedBy: "Reserved_A" diff --git a/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml b/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml new file mode 100644 index 000000000..431776e0f --- /dev/null +++ b/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml @@ -0,0 +1,13 @@ +--- +#################################################### +# Configuration as Code config file for unit tests # +#################################################### +jenkins: + systemMessage: "Welcome to the Lockable Resource Jenkins Server" +unclassified: + lockableResourcesManager: + declaredResources: + - description: "Description_A" + labels: "Label_A" + name: "Resource_A" + reservedBy: "Reserved_A" From 0cdf4be9fcc9c3cefd6c14d11a2b1d943b30308e Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 22:36:48 +0200 Subject: [PATCH 0038/1078] Fix readme order --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dee2e3224..d2be67c88 100644 --- a/README.md +++ b/README.md @@ -69,17 +69,13 @@ lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { } ``` -## Changelog - -* See [GitHub Releases](https://github.com/jenkinsci/lockable-resources-plugin/releases) - for recent versions -* See the [plugin's Wiki page](https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin#LockableResourcesPlugin-Changelog) - for versions 2.5 and older - ## Configuration as Code -This plugin can be configured via [Configuration-as-Code](https://github.com/jenkinsci/configuration-as-code-plugin). + +This plugin can be configured via +[Configuration-as-Code](https://github.com/jenkinsci/configuration-as-code-plugin). ### Example configuration + ``` unclassified: lockableResourcesManager: @@ -90,6 +86,13 @@ unclassified: reservedBy: "Reserved_A" ``` +## Changelog + +* See [GitHub Releases](https://github.com/jenkinsci/lockable-resources-plugin/releases) + for recent versions +* See the [plugin's Wiki page](https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin#LockableResourcesPlugin-Changelog) + for versions 2.5 and older + ## Contributing If you want to contribute to this plugin, you probably will need a Jenkins plugin developement From e0d1e37504d2ce67241b65ad755ea3eb7fc92007 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 4 Oct 2019 00:32:33 +0200 Subject: [PATCH 0039/1078] Disable parallel tests again They don't seem to be stable... --- pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5e1392e40..9f0588c07 100644 --- a/pom.xml +++ b/pom.xml @@ -56,8 +56,6 @@ 2.12 2.60.3 1.25 - - 1C From 80109a6bc2560160261b44dc470955e8a61476ae Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 23:13:54 +0200 Subject: [PATCH 0040/1078] Format LockStep(Test) --- .../plugins/lockableresources/LockStep.java | 249 +++++++++--------- .../lockableresources/LockStepTest.java | 19 +- 2 files changed, 132 insertions(+), 136 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 0944aa941..b08fa7e81 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -1,142 +1,135 @@ package org.jenkins.plugins.lockableresources; +import edu.umd.cs.findbugs.annotations.CheckForNull; +import hudson.Extension; +import hudson.model.AutoCompletionCandidates; +import hudson.util.FormValidation; import java.io.Serializable; import java.util.ArrayList; import java.util.List; - import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; -import hudson.Extension; -import hudson.model.AutoCompletionCandidates; -import hudson.util.FormValidation; - -import edu.umd.cs.findbugs.annotations.CheckForNull; - public class LockStep extends AbstractStepImpl implements Serializable { - @CheckForNull - public String resource = null; - - @CheckForNull - public String label = null; - - public int quantity = 0; - - /** name of environment variable to store locked resources in */ - @CheckForNull - public String variable = null; - - public boolean inversePrecedence = false; - - @CheckForNull - public List extra = null; - - // it should be LockStep() - without params. But keeping this for backward compatibility - // so `lock('resource1')` still works and `lock(label: 'label1', quantity: 3)` works too (resource is not required) - @DataBoundConstructor - public LockStep(String resource) { - if (resource != null && !resource.isEmpty()) { - this.resource = resource; - } - } - - @DataBoundSetter - public void setInversePrecedence(boolean inversePrecedence) { - this.inversePrecedence = inversePrecedence; - } - - @DataBoundSetter - public void setLabel(String label) { - if (label != null && !label.isEmpty()) { - this.label = label; - } - } - - @DataBoundSetter - public void setVariable(String variable) { - if (variable != null && !variable.isEmpty()) { - this.variable = variable; - } - } - - @DataBoundSetter - public void setQuantity(int quantity) { - this.quantity = quantity; - } - - @DataBoundSetter - public void setExtra(List extra) { - this.extra = extra; - } - - @Extension - public static final class DescriptorImpl extends AbstractStepDescriptorImpl { - - public DescriptorImpl() { - super(LockStepExecution.class); - } - - @Override - public String getFunctionName() { - return "lock"; - } - - @Override - public String getDisplayName() { - return "Lock shared resource"; - } - - @Override - public boolean takesImplicitBlockArgument() { - return true; - } - - public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value) { - return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value); - } - - public static FormValidation doCheckLabel(@QueryParameter String value, @QueryParameter String resource) { - return LockStepResource.DescriptorImpl.doCheckLabel(value, resource); - } - - public static FormValidation doCheckResource(@QueryParameter String value, @QueryParameter String label) { - return LockStepResource.DescriptorImpl.doCheckLabel(label, value); - } - } - - public String toString() { - if (extra != null && !extra.isEmpty()) { - StringBuilder builder = new StringBuilder(); - for (LockStepResource resource : getResources()) { - builder.append("{" + resource.toString() + "},"); - } - return builder.toString(); - } else { - return LockStepResource.toString(resource, label, quantity); - } - } - - /** - * Label and resource are mutual exclusive. - */ - public void validate() throws Exception { - LockStepResource.validate(resource, label, quantity); - } - - public List getResources() { - List resources = new ArrayList<>(); - resources.add(new LockStepResource(resource, label, quantity)); - - if (extra != null) { - resources.addAll(extra); - } - return resources; - } - - private static final long serialVersionUID = 1L; - + private static final long serialVersionUID = 1L; + + @CheckForNull public String resource = null; + + @CheckForNull public String label = null; + + public int quantity = 0; + + /** name of environment variable to store locked resources in */ + @CheckForNull public String variable = null; + + public boolean inversePrecedence = false; + + @CheckForNull public List extra = null; + + // it should be LockStep() - without params. But keeping this for backward compatibility + // so `lock('resource1')` still works and `lock(label: 'label1', quantity: 3)` works too (resource + // is not required) + @DataBoundConstructor + public LockStep(String resource) { + if (resource != null && !resource.isEmpty()) { + this.resource = resource; + } + } + + @DataBoundSetter + public void setInversePrecedence(boolean inversePrecedence) { + this.inversePrecedence = inversePrecedence; + } + + @DataBoundSetter + public void setLabel(String label) { + if (label != null && !label.isEmpty()) { + this.label = label; + } + } + + @DataBoundSetter + public void setVariable(String variable) { + if (variable != null && !variable.isEmpty()) { + this.variable = variable; + } + } + + @DataBoundSetter + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + @DataBoundSetter + public void setExtra(List extra) { + this.extra = extra; + } + + @Extension + public static final class DescriptorImpl extends AbstractStepDescriptorImpl { + + public DescriptorImpl() { + super(LockStepExecution.class); + } + + @Override + public String getFunctionName() { + return "lock"; + } + + @Override + public String getDisplayName() { + return "Lock shared resource"; + } + + @Override + public boolean takesImplicitBlockArgument() { + return true; + } + + public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value) { + return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value); + } + + public static FormValidation doCheckLabel( + @QueryParameter String value, @QueryParameter String resource) { + return LockStepResource.DescriptorImpl.doCheckLabel(value, resource); + } + + public static FormValidation doCheckResource( + @QueryParameter String value, @QueryParameter String label) { + return LockStepResource.DescriptorImpl.doCheckLabel(label, value); + } + } + + public String toString() { + if (extra != null && !extra.isEmpty()) { + StringBuilder builder = new StringBuilder(); + for (LockStepResource resource : getResources()) { + builder.append("{" + resource.toString() + "},"); + } + return builder.toString(); + } else { + return LockStepResource.toString(resource, label, quantity); + } + } + + /** Label and resource are mutual exclusive. */ + public void validate() throws Exception { + LockStepResource.validate(resource, label, quantity); + } + + public List getResources() { + List resources = new ArrayList<>(); + resources.add(new LockStepResource(resource, label, quantity)); + + if (extra != null) { + resources.addAll(extra); + } + return resources; + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 979d5ac1e..403d17213 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -337,7 +337,8 @@ public void parallelLock() throws Exception { // both messages are in the log because branch b acquired the lock and branch a is waiting to // lock j.waitForMessage("[b] Lock acquired on [resource1]", b1); - j.waitForMessage("[a] [resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); + j.waitForMessage( + "[a] [resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); isPaused(b1, 2, 1); SemaphoreStep.success("wait-b/1", null); @@ -454,7 +455,8 @@ public void unlockButtonWithWaitingRuns() throws Exception { for (int i = 0; i < 3; i++) { WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); if (prevBuild != null) { - j.waitForMessage("[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); + j.waitForMessage( + "[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); wc.goTo("lockable-resources/unlock?resource=resource1"); } @@ -496,7 +498,8 @@ public void parallelLockRelease() throws Exception { for (int i = 0; i < 5; i++) { WorkflowRun rNext = job.scheduleBuild2(0).waitForStart(); if (toUnlock != null) { - j.waitForMessage("[resource1] is locked by " + toUnlock.getFullDisplayName() + ", waiting...", rNext); + j.waitForMessage( + "[resource1] is locked by " + toUnlock.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); SemaphoreStep.success("wait-inside-1/" + i, null); } @@ -829,11 +832,11 @@ public void lockWithInvalidLabel() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( - new CpsFlowDefinition( - "lock(label: 'invalidLabel', variable: 'var', quantity: 1) {\n" + - " echo \"Resource locked: ${env.var}\"\n" + - "}\n" + - "echo 'Finish'")); + new CpsFlowDefinition( + "lock(label: 'invalidLabel', variable: 'var', quantity: 1) {\n" + + " echo \"Resource locked: ${env.var}\"\n" + + "}\n" + + "echo 'Finish'")); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.FAILURE, b1); From 7e2c6381f30fe9608ece5939cdccc431e1878f1d Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 23:37:05 +0200 Subject: [PATCH 0041/1078] Allow locking "nothing" This seems to be useless, but can be useful in a pipeline when dynamically constructing the list of resources which should be locked. (Actually, this was already possible, but the output suggested this would have been a bug) --- .../plugins/lockableresources/LockStep.java | 8 +++++-- .../lockableresources/LockStepTest.java | 22 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index b08fa7e81..f946c6de8 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -113,8 +113,10 @@ public String toString() { builder.append("{" + resource.toString() + "},"); } return builder.toString(); - } else { + } else if (resource != null || label != null) { return LockStepResource.toString(resource, label, quantity); + } else { + return "nothing"; } } @@ -125,7 +127,9 @@ public void validate() throws Exception { public List getResources() { List resources = new ArrayList<>(); - resources.add(new LockStepResource(resource, label, quantity)); + if (resource != null || label != null) { + resources.add(new LockStepResource(resource, label, quantity)); + } if (extra != null) { resources.addAll(extra); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 403d17213..dbd284598 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -66,6 +66,18 @@ public void autoCreateResourceFreeStyle() throws IOException, InterruptedExcepti assertNull(LockableResourcesManager.get().fromName("resource1")); } + @Test + public void lockNothing() throws Exception { + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock() {\n" + " echo 'Nothing locked.'\n" + "}\n" + "echo 'Finish'")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Lock acquired on [nothing]", b1); + } + @Test public void lockWithLabel() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); @@ -761,11 +773,11 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock(resource: 'resource4', variable: 'var', extra: [[resource: 'resource2'], [label: 'label1', quantity: 2]]) {\n" - + " def lockedResources = env.var.split(',')\n" - + " Arrays.sort(lockedResources)\n" - + " echo \"Resources locked: ${lockedResources}\"\n" - + " semaphore 'wait-inside'\n" + "lock(variable: 'var', extra: [[resource: 'resource4'], [resource: 'resource2'], [label: 'label1', quantity: 2]]) {\n" + + " def lockedResources = env.var.split(',')\n" + + " Arrays.sort(lockedResources)\n" + + " echo \"Resources locked: ${lockedResources}\"\n" + + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'")); // #1 should lock as few resources as possible From e61fc4d040c7236998302f4cd6e9891171880f8d Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 1 Oct 2019 23:48:38 +0200 Subject: [PATCH 0042/1078] Drop stray comma at the end of a resource list --- .../org/jenkins/plugins/lockableresources/LockStep.java | 9 ++++----- .../jenkins/plugins/lockableresources/LockStepTest.java | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index f946c6de8..bedff670a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; import org.kohsuke.stapler.DataBoundConstructor; @@ -108,11 +109,9 @@ public static FormValidation doCheckResource( public String toString() { if (extra != null && !extra.isEmpty()) { - StringBuilder builder = new StringBuilder(); - for (LockStepResource resource : getResources()) { - builder.append("{" + resource.toString() + "},"); - } - return builder.toString(); + return getResources().stream() + .map(resource -> "{" + resource.toString() + "}") + .collect(Collectors.joining(",")); } else if (resource != null || label != null) { return LockStepResource.toString(resource, label, quantity); } else { diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index dbd284598..19b3e0b20 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -644,7 +644,7 @@ public void lockMultipleResources() throws Exception { // Unlock resources SemaphoreStep.success("wait-inside/1", null); - j.waitForMessage("Lock released on resource [{resource1},{resource2},]", b1); + j.waitForMessage("Lock released on resource [{resource1},{resource2}]", b1); isPaused(b1, 1, 0); // Both get their lock @@ -695,7 +695,7 @@ public void lockWithLabelAndResource() throws Exception { // Unlock resources SemaphoreStep.success("wait-inside/1", null); - j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); + j.waitForMessage("Lock released on resource [{Label: label1},{resource1}]", b1); isPaused(b2, 1, 0); // Both get their lock @@ -746,7 +746,7 @@ public void lockWithLabelAndLabeledResource() throws Exception { // Unlock resources SemaphoreStep.success("wait-inside/1", null); - j.waitForMessage("Lock released on resource [{Label: label1},{resource1},]", b1); + j.waitForMessage("Lock released on resource [{Label: label1},{resource1}]", b1); isPaused(b1, 1, 0); // #2 gets the lock before #3 (in the order as they requested the lock) @@ -821,7 +821,7 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { // Unlock resources SemaphoreStep.success("wait-inside/1", null); j.waitForMessage( - "Lock released on resource [{resource4},{resource2},{Label: label1, Quantity: 2},]", b1); + "Lock released on resource [{resource4},{resource2},{Label: label1, Quantity: 2}]", b1); j.assertLogContains("Resources locked: [resource2, resource4]", b1); isPaused(b1, 1, 0); From 939194bf613a573b339616833db8ceb57818b843 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Thu, 10 Oct 2019 23:14:43 +0200 Subject: [PATCH 0043/1078] Format classes with inconsistent indentation --- .../lockableresources/LockableResource.java | 626 ++++--- .../LockableResourcesManager.java | 1517 +++++++++-------- 2 files changed, 1093 insertions(+), 1050 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 468bc2b45..83a319324 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -8,124 +8,117 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package org.jenkins.plugins.lockableresources; +import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.CheckForNull; import groovy.lang.Binding; import hudson.Extension; import hudson.Util; -import hudson.model.AbstractDescribableImpl; import hudson.model.AbstractBuild; +import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; import hudson.model.Queue; -import hudson.model.Run; import hudson.model.Queue.Item; import hudson.model.Queue.Task; +import hudson.model.Run; import hudson.model.User; import hudson.tasks.Mailer.UserProperty; - import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; - +import javax.annotation.Nonnull; import jenkins.model.Jenkins; - import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; -import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +@ExportedBean(defaultVisibility = 999) +public class LockableResource extends AbstractDescribableImpl + implements Serializable { + + private static final Logger LOGGER = Logger.getLogger(LockableResource.class.getName()); + public static final int NOT_QUEUED = 0; + private static final int QUEUE_TIMEOUT = 60; + public static final String GROOVY_LABEL_MARKER = "groovy:"; + + private final String name; + private String description = ""; + private String labels = ""; + private String reservedBy = null; + private boolean ephemeral; -import edu.umd.cs.findbugs.annotations.CheckForNull; -import java.util.concurrent.ExecutionException; + private long queueItemId = NOT_QUEUED; + private String queueItemProject = null; + private transient Run build = null; + // Needed to make the state non-transient + private String buildExternalizableId = null; + private long queuingStarted = 0; + + /** + * Was used within the initial implementation of Pipeline functionality using {@link LockStep}, + * but became deprecated once several resources could be locked at once. See queuedContexts in + * {@link LockableResourcesManager}. + */ + @Deprecated private List queuedContexts = new ArrayList<>(); + + @Deprecated + public LockableResource(String name, String description, String labels, String reservedBy) { + this.name = name; + this.description = description; + this.labels = labels; + this.reservedBy = Util.fixEmptyAndTrim(reservedBy); + } -import javax.annotation.Nonnull; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; + @DataBoundConstructor + public LockableResource(String name) { + this.name = name; + } -@ExportedBean(defaultVisibility = 999) -public class LockableResource extends AbstractDescribableImpl implements Serializable { + private Object readResolve() { + if (queuedContexts == null) { // this field was added after the initial version if this class + queuedContexts = new ArrayList<>(); + } + return this; + } - private static final Logger LOGGER = Logger.getLogger(LockableResource.class.getName()); - public static final int NOT_QUEUED = 0; - private static final int QUEUE_TIMEOUT = 60; - public static final String GROOVY_LABEL_MARKER = "groovy:"; + @Deprecated + public List getQueuedContexts() { + return this.queuedContexts; + } - private final String name; - private String description = ""; - private String labels = ""; - private String reservedBy = null; - private boolean ephemeral; + @DataBoundSetter + public void setDescription(String description) { + this.description = description; + } + + @DataBoundSetter + public void setLabels(String labels) { + this.labels = labels; + } + + @Exported + public String getName() { + return name; + } - private long queueItemId = NOT_QUEUED; - private String queueItemProject = null; - private transient Run build = null; - // Needed to make the state non-transient - private String buildExternalizableId = null; - private long queuingStarted = 0; - - /** - * Was used within the initial implementation of Pipeline functionality - * using {@link LockStep}, but became deprecated once several resources - * could be locked at once. See queuedContexts in {@link LockableResourcesManager}. - */ - @Deprecated - private List queuedContexts = new ArrayList<>(); - - @Deprecated - public LockableResource( - String name, String description, String labels, String reservedBy) { - this.name = name; - this.description = description; - this.labels = labels; - this.reservedBy = Util.fixEmptyAndTrim(reservedBy); - } - - @DataBoundConstructor - public LockableResource(String name) { - this.name = name; - } - - private Object readResolve() { - if (queuedContexts == null) { // this field was added after the initial version if this class - queuedContexts = new ArrayList<>(); - } - return this; - } - - @Deprecated - public List getQueuedContexts() { - return this.queuedContexts; - } - - @DataBoundSetter - public void setDescription(String description) { - this.description = description; - } - - @DataBoundSetter - public void setLabels(String labels) { - this.labels = labels; - } - - @Exported - public String getName() { - return name; - } - - @Exported - public String getDescription() { - return description; - } - - @Exported - public String getLabels() { - return labels; - } + @Exported + public String getDescription() { + return description; + } + + @Exported + public String getLabels() { + return labels; + } @DataBoundSetter public void setEphemeral(boolean ephemeral) { @@ -137,234 +130,233 @@ public boolean isEphemeral() { return ephemeral; } - public boolean isValidLabel(String candidate, Map params) { - return labelsContain(candidate); - } - - private boolean labelsContain(String candidate) { - return makeLabelsList().contains(candidate); - } - - private List makeLabelsList() { - return Arrays.asList(labels.split("\\s+")); - } - - /** - * Checks if the script matches the requirement. - * @param script Script to be executed - * @param params Extra script parameters - * @return {@code true} if the script returns true (resource matches). - * @throws ExecutionException Script execution failed (e.g. due to the missing permissions). Carries info in the cause - */ - @Restricted(NoExternalUse.class) - public boolean scriptMatches(@Nonnull SecureGroovyScript script, @CheckForNull Map params) - throws ExecutionException { - Binding binding = new Binding(params); - binding.setVariable("resourceName", name); - binding.setVariable("resourceDescription", description); - binding.setVariable("resourceLabels", makeLabelsList()); - try { - Object result = script.evaluate(Jenkins.getInstance().getPluginManager().uberClassLoader, binding); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Checked resource " + name + " for " + script.getScript() - + " with " + binding + " -> " + result); - } - return (Boolean) result; - } catch (Exception e) { - throw new ExecutionException("Cannot get boolean result out of groovy expression. See system log for more info", e); - } - } - - @Exported - public String getReservedBy() { - return reservedBy; - } - - @Exported - public boolean isReserved() { - return reservedBy != null; - } - - @Exported - public String getReservedByEmail() { - if (reservedBy != null) { - UserProperty email = null; - User user = Jenkins.getInstance().getUser(reservedBy); - if (user != null) - email = user.getProperty(UserProperty.class); - if (email != null) - return email.getAddress(); - } - return null; - } - - public boolean isQueued() { - this.validateQueuingTimeout(); - return queueItemId != NOT_QUEUED; - } - - // returns True if queued by any other task than the given one - public boolean isQueued(long taskId) { - this.validateQueuingTimeout(); - return queueItemId != NOT_QUEUED && queueItemId != taskId; - } - - public boolean isQueuedByTask(long taskId) { - this.validateQueuingTimeout(); - return queueItemId == taskId; - } - - public void unqueue() { - queueItemId = NOT_QUEUED; - queueItemProject = null; - queuingStarted = 0; - } - - @Exported - public boolean isLocked() { - return getBuild() != null; - } - - /** - * Resolve the lock cause for this resource. It can be reserved or locked. - * - * @return the lock cause or null if not locked - */ - @CheckForNull - public String getLockCause() { - if (isReserved()) { - return String.format("[%s] is reserved by %s", name, reservedBy); - } - if (isLocked()) { - return String.format("[%s] is locked by %s", name, buildExternalizableId); - } - return null; - } - - @WithBridgeMethods(value=AbstractBuild.class, adapterMethod="getAbstractBuild") - public Run getBuild() { - if (build == null && buildExternalizableId != null) { - build = Run.fromExternalizableId(buildExternalizableId); - } - return build; - } - - /** - * @see {@link WithBridgeMethods} - */ - @Deprecated - private Object getAbstractBuild(final Run owner, final Class targetClass) { - return owner instanceof AbstractBuild ? (AbstractBuild) owner : null; - } - - @Exported - public String getBuildName() { - if (getBuild() != null) - return getBuild().getFullDisplayName(); - else - return null; - } - - public void setBuild(Run lockedBy) { - this.build = lockedBy; - if (lockedBy != null) { - this.buildExternalizableId = lockedBy.getExternalizableId(); - } else { - this.buildExternalizableId = null; - } - } - - public Task getTask() { - Item item = Queue.getInstance().getItem(queueItemId); - if (item != null) { - return item.task; - } else { - return null; - } - } - - public long getQueueItemId() { - this.validateQueuingTimeout(); - return queueItemId; - } - - public String getQueueItemProject() { - this.validateQueuingTimeout(); - return this.queueItemProject; - } - - public void setQueued(long queueItemId) { - this.queueItemId = queueItemId; - this.queuingStarted = System.currentTimeMillis() / 1000; - } - - public void setQueued(long queueItemId, String queueProjectName) { - this.setQueued(queueItemId); - this.queueItemProject = queueProjectName; - } - - private void validateQueuingTimeout() { - if (queuingStarted > 0) { - long now = System.currentTimeMillis() / 1000; - if (now - queuingStarted > QUEUE_TIMEOUT) - unqueue(); - } - } - - @DataBoundSetter - public void setReservedBy(String userName) { - this.reservedBy = Util.fixEmptyAndTrim(userName); - } - - public void unReserve() { - this.reservedBy = null; - } - - public void reset() { - this.unReserve(); - this.unqueue(); - this.setBuild(null); - } - - @Override - public String toString() { - return name; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - LockableResource other = (LockableResource) obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; - } - - @Extension - public static class DescriptorImpl extends Descriptor { - - @Override - public String getDisplayName() { - return "Resource"; - } - - } - - private static final long serialVersionUID = 1L; + public boolean isValidLabel(String candidate, Map params) { + return labelsContain(candidate); + } + + private boolean labelsContain(String candidate) { + return makeLabelsList().contains(candidate); + } + + private List makeLabelsList() { + return Arrays.asList(labels.split("\\s+")); + } + + /** + * Checks if the script matches the requirement. + * + * @param script Script to be executed + * @param params Extra script parameters + * @return {@code true} if the script returns true (resource matches). + * @throws ExecutionException Script execution failed (e.g. due to the missing permissions). + * Carries info in the cause + */ + @Restricted(NoExternalUse.class) + public boolean scriptMatches( + @Nonnull SecureGroovyScript script, @CheckForNull Map params) + throws ExecutionException { + Binding binding = new Binding(params); + binding.setVariable("resourceName", name); + binding.setVariable("resourceDescription", description); + binding.setVariable("resourceLabels", makeLabelsList()); + try { + Object result = + script.evaluate(Jenkins.getInstance().getPluginManager().uberClassLoader, binding); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine( + "Checked resource " + + name + + " for " + + script.getScript() + + " with " + + binding + + " -> " + + result); + } + return (Boolean) result; + } catch (Exception e) { + throw new ExecutionException( + "Cannot get boolean result out of groovy expression. See system log for more info", e); + } + } + + @Exported + public String getReservedBy() { + return reservedBy; + } + + @Exported + public boolean isReserved() { + return reservedBy != null; + } + + @Exported + public String getReservedByEmail() { + if (reservedBy != null) { + UserProperty email = null; + User user = Jenkins.getInstance().getUser(reservedBy); + if (user != null) email = user.getProperty(UserProperty.class); + if (email != null) return email.getAddress(); + } + return null; + } + + public boolean isQueued() { + this.validateQueuingTimeout(); + return queueItemId != NOT_QUEUED; + } + + // returns True if queued by any other task than the given one + public boolean isQueued(long taskId) { + this.validateQueuingTimeout(); + return queueItemId != NOT_QUEUED && queueItemId != taskId; + } + + public boolean isQueuedByTask(long taskId) { + this.validateQueuingTimeout(); + return queueItemId == taskId; + } + + public void unqueue() { + queueItemId = NOT_QUEUED; + queueItemProject = null; + queuingStarted = 0; + } + + @Exported + public boolean isLocked() { + return getBuild() != null; + } + + /** + * Resolve the lock cause for this resource. It can be reserved or locked. + * + * @return the lock cause or null if not locked + */ + @CheckForNull + public String getLockCause() { + if (isReserved()) { + return String.format("[%s] is reserved by %s", name, reservedBy); + } + if (isLocked()) { + return String.format("[%s] is locked by %s", name, buildExternalizableId); + } + return null; + } + + @WithBridgeMethods(value = AbstractBuild.class, adapterMethod = "getAbstractBuild") + public Run getBuild() { + if (build == null && buildExternalizableId != null) { + build = Run.fromExternalizableId(buildExternalizableId); + } + return build; + } + + /** @see {@link WithBridgeMethods} */ + @Deprecated + private Object getAbstractBuild(final Run owner, final Class targetClass) { + return owner instanceof AbstractBuild ? (AbstractBuild) owner : null; + } + + @Exported + public String getBuildName() { + if (getBuild() != null) return getBuild().getFullDisplayName(); + else return null; + } + + public void setBuild(Run lockedBy) { + this.build = lockedBy; + if (lockedBy != null) { + this.buildExternalizableId = lockedBy.getExternalizableId(); + } else { + this.buildExternalizableId = null; + } + } + + public Task getTask() { + Item item = Queue.getInstance().getItem(queueItemId); + if (item != null) { + return item.task; + } else { + return null; + } + } + + public long getQueueItemId() { + this.validateQueuingTimeout(); + return queueItemId; + } + + public String getQueueItemProject() { + this.validateQueuingTimeout(); + return this.queueItemProject; + } + + public void setQueued(long queueItemId) { + this.queueItemId = queueItemId; + this.queuingStarted = System.currentTimeMillis() / 1000; + } + + public void setQueued(long queueItemId, String queueProjectName) { + this.setQueued(queueItemId); + this.queueItemProject = queueProjectName; + } + + private void validateQueuingTimeout() { + if (queuingStarted > 0) { + long now = System.currentTimeMillis() / 1000; + if (now - queuingStarted > QUEUE_TIMEOUT) unqueue(); + } + } + + @DataBoundSetter + public void setReservedBy(String userName) { + this.reservedBy = Util.fixEmptyAndTrim(userName); + } + + public void unReserve() { + this.reservedBy = null; + } + + public void reset() { + this.unReserve(); + this.unqueue(); + this.setBuild(null); + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + LockableResource other = (LockableResource) obj; + if (name == null) { + if (other.name != null) return false; + } else if (!name.equals(other.name)) return false; + return true; + } + + @Extension + public static class DescriptorImpl extends Descriptor { + + @Override + public String getDisplayName() { + return "Resource"; + } + } + + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 7f4c36e7d..57b0c41f2 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -9,59 +9,51 @@ package org.jenkins.plugins.lockableresources; import edu.umd.cs.findbugs.annotations.CheckForNull; -import hudson.Extension; +import edu.umd.cs.findbugs.annotations.Nullable; import hudson.BulkChange; +import hudson.Extension; import hudson.model.Run; - +import hudson.model.TaskListener; import java.io.IOException; import java.io.PrintStream; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; - -import hudson.model.TaskListener; +import javax.annotation.Nonnull; import jenkins.model.GlobalConfiguration; import jenkins.model.Jenkins; -import net.sf.json.JSONException; import net.sf.json.JSONObject; - import org.apache.commons.lang.StringUtils; import org.jenkins.plugins.lockableresources.queue.LockableResourcesCandidatesStruct; import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; -import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct; +import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.workflow.steps.StepContext; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; -import edu.umd.cs.findbugs.annotations.Nullable; -import javax.annotation.Nonnull; - @Extension public class LockableResourcesManager extends GlobalConfiguration { - @Deprecated - private transient int defaultPriority; - @Deprecated - private transient String priorityParameterName; - private List resources; + @Deprecated private transient int defaultPriority; + @Deprecated private transient String priorityParameterName; + private List resources; + /** + * Only used when this lockable resource is tried to be locked by {@link LockStep}, otherwise + * (freestyle builds) regular Jenkins queue is used. + */ + private List queuedContexts = new ArrayList<>(); - /** - * Only used when this lockable resource is tried to be locked by {@link LockStep}, - * otherwise (freestyle builds) regular Jenkins queue is used. - */ - private List queuedContexts = new ArrayList<>(); - - public LockableResourcesManager() { - resources = new ArrayList<>(); - load(); - } + public LockableResourcesManager() { + resources = new ArrayList<>(); + load(); + } - public List getResources() { - return resources; - } + public List getResources() { + return resources; + } public synchronized List getDeclaredResources() { ArrayList declaredResources = new ArrayList<>(); @@ -111,573 +103,621 @@ public synchronized void setDeclaredResources(List declaredRes this.resources = mergedResources; } - public List getResourcesFromProject(String fullName) { - List matching = new ArrayList<>(); - for (LockableResource r : resources) { - String rName = r.getQueueItemProject(); - if (rName != null && rName.equals(fullName)) { - matching.add(r); - } - } - return matching; - } - - public List getResourcesFromBuild(Run build) { - List matching = new ArrayList<>(); - for (LockableResource r : resources) { - Run rBuild = r.getBuild(); - if (rBuild != null && rBuild == build) { - matching.add(r); - } - } - return matching; - } - - public Boolean isValidLabel(String label) - { - return this.getAllLabels().contains(label); - } - - public Set getAllLabels() - { - Set labels = new HashSet<>(); - for (LockableResource r : this.resources) { - String rl = r.getLabels(); - if (rl == null || "".equals(rl)) - continue; - labels.addAll(Arrays.asList(rl.split("\\s+"))); - } - return labels; - } - - public int getFreeResourceAmount(String label) - { - int free = 0; - for (LockableResource r : this.resources) { - if (r.isLocked() || r.isQueued() || r.isReserved()) - continue; - if (Arrays.asList(r.getLabels().split("\\s+")).contains(label)) - free += 1; - } - return free; - } - - public List getResourcesWithLabel(String label, - Map params) { - List found = new ArrayList<>(); - for (LockableResource r : this.resources) { - if (r.isValidLabel(label, params)) - found.add(r); - } - return found; - } - - /** - * Get a list of resources matching the script. - * @param script Script - * @param params Additional parameters - * @return List of the matching resources - * @throws ExecutionException Script execution failed for one of the resources. - * It is considered as a fatal failure since the requirement list may be incomplete - * @since TODO - */ - @Nonnull - public List getResourcesMatchingScript(@Nonnull SecureGroovyScript script, - @CheckForNull Map params) throws ExecutionException{ - List found = new ArrayList<>(); - for (LockableResource r : this.resources) { - if (r.scriptMatches(script, params)) - found.add(r); - } - return found; - } - - public LockableResource fromName(String resourceName) { - if (resourceName != null) { - for (LockableResource r : resources) { - if (resourceName.equals(r.getName())) - return r; - } - } - return null; - } - - public synchronized boolean queue(List resources, - long queueItemId, String queueProjectName) { - for (LockableResource r : resources) - if (r.isReserved() || r.isQueued(queueItemId) || r.isLocked()) - return false; - for (LockableResource r : resources) { - r.setQueued(queueItemId, queueProjectName); - } - return true; - } - - /** - * @deprecated USe {@link #tryQueue(org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct, long, java.lang.String, int, java.util.Map, java.util.logging.Logger)} - */ - @Deprecated - @CheckForNull - public synchronized List queue(LockableResourcesStruct requiredResources, - long queueItemId, - String queueItemProject, - int number, // 0 means all - Map params, - Logger log) { - try { - return tryQueue(requiredResources, queueItemId, queueItemProject, number, params, log); - } catch(ExecutionException ex) { - if (LOGGER.isLoggable(Level.WARNING)) { - String itemName = queueItemProject + " (id=" + queueItemId + ")"; - LOGGER.log(Level.WARNING, "Failed to queue item " + itemName, ex.getCause() != null ? ex.getCause() : ex); - } - return null; - } - } - - /** - * Try to acquire the resources required by the task. - * @param number Number of resources to acquire. {@code 0} means all - * @return List of the locked resources if the task has been accepted. - * {@code null} if the item is still waiting for the resources - * @throws ExecutionException Cannot queue the resource due to the execution failure. Carries info in the cause - * @since TODO - */ - @CheckForNull - public synchronized List tryQueue(LockableResourcesStruct requiredResources, - long queueItemId, String queueItemProject, int number, - Map params, Logger log) throws ExecutionException { - List selected = new ArrayList<>(); - - if (!checkCurrentResourcesStatus(selected, queueItemProject, queueItemId, log)) { - // The project has another buildable item waiting -> bail out - log.log(Level.FINEST, "{0} has another build waiting resources." + - " Waiting for it to proceed first.", - new Object[]{queueItemProject}); - return null; - } - - boolean candidatesByScript=false; - List candidates = new ArrayList<>(); - final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); - if (requiredResources.label != null && requiredResources.label.isEmpty() && systemGroovyScript == null) { - candidates = requiredResources.required; - } else if (systemGroovyScript == null) { - candidates = getResourcesWithLabel(requiredResources.label, params); - } else { - candidates = getResourcesMatchingScript(systemGroovyScript, params); - candidatesByScript = true; - } - - for (LockableResource rs : candidates) { - if (number != 0 && (selected.size() >= number)) - break; - if (!rs.isReserved() && !rs.isLocked() && !rs.isQueued()) - selected.add(rs); - } - - // if did not get wanted amount or did not get all - final int required_amount; - if (candidatesByScript && candidates.isEmpty()) { - /** - * If the groovy script does not return any candidates, it means nothing is needed, even - * if a higher amount is specified. A valid use case is a Matrix job, when not all - * configurations need resources. - */ - required_amount = 0; - } else { - required_amount = number == 0 ? candidates.size() : number; - } - - if (selected.size() != required_amount) { - log.log(Level.FINEST, "{0} found {1} resource(s) to queue." + - "Waiting for correct amount: {2}.", - new Object[]{queueItemProject, selected.size(), required_amount}); - // just to be sure, clean up - for (LockableResource x : resources) { - if (x.getQueueItemProject() != null && - x.getQueueItemProject().equals(queueItemProject)) - x.unqueue(); - } - return null; - } - - for (LockableResource rsc : selected) { - rsc.setQueued(queueItemId, queueItemProject); - } - return selected; - } - - // Adds already selected (in previous queue round) resources to 'selected' - // Return false if another item queued for this project -> bail out - private boolean checkCurrentResourcesStatus(List selected, - String project, - long taskId, - Logger log) { - for (LockableResource r : resources) { - // This project might already have something in queue - String rProject = r.getQueueItemProject(); - if (rProject != null && rProject.equals(project)) { - if (r.isQueuedByTask(taskId)) { - // this item has queued the resource earlier - selected.add(r); - } else { - // The project has another buildable item waiting -> bail out - log.log(Level.FINEST, "{0} has another build " + - "that already queued resource {1}. Continue queueing.", - new Object[]{project, r}); - return false; - } - } - } - return true; - } - - public synchronized boolean lock(Set resources, Run build, @Nullable StepContext context) { - return lock(resources, build, context, null, null, false); - } - - /** - * Try to lock the resource and return true if locked. - */ - public synchronized boolean lock(Set resources, - Run build, @Nullable StepContext context, @Nullable String logmessage, - final String variable, boolean inversePrecedence) { - boolean needToWait = false; - - for (LockableResource r : resources) { - if (r.isReserved() || r.isLocked()) { - needToWait = true; - break; - } - } - if (!needToWait) { - for (LockableResource r : resources) { - r.unqueue(); - r.setBuild(build); - } - if (context != null) { - // since LockableResource contains transient variables, they cannot be correctly serialized - // hence we use their unique resource names - List resourceNames = new ArrayList<>(); - for (LockableResource resource : resources) { - resourceNames.add(resource.getName()); - } - LockStepExecution.proceed(resourceNames, context, logmessage, variable, inversePrecedence); - } + public List getResourcesFromProject(String fullName) { + List matching = new ArrayList<>(); + for (LockableResource r : resources) { + String rName = r.getQueueItemProject(); + if (rName != null && rName.equals(fullName)) { + matching.add(r); + } + } + return matching; + } + + public List getResourcesFromBuild(Run build) { + List matching = new ArrayList<>(); + for (LockableResource r : resources) { + Run rBuild = r.getBuild(); + if (rBuild != null && rBuild == build) { + matching.add(r); + } + } + return matching; + } + + public Boolean isValidLabel(String label) { + return this.getAllLabels().contains(label); + } + + public Set getAllLabels() { + Set labels = new HashSet<>(); + for (LockableResource r : this.resources) { + String rl = r.getLabels(); + if (rl == null || "".equals(rl)) continue; + labels.addAll(Arrays.asList(rl.split("\\s+"))); + } + return labels; + } + + public int getFreeResourceAmount(String label) { + int free = 0; + for (LockableResource r : this.resources) { + if (r.isLocked() || r.isQueued() || r.isReserved()) continue; + if (Arrays.asList(r.getLabels().split("\\s+")).contains(label)) free += 1; + } + return free; + } + + public List getResourcesWithLabel(String label, Map params) { + List found = new ArrayList<>(); + for (LockableResource r : this.resources) { + if (r.isValidLabel(label, params)) found.add(r); + } + return found; + } + + /** + * Get a list of resources matching the script. + * + * @param script Script + * @param params Additional parameters + * @return List of the matching resources + * @throws ExecutionException Script execution failed for one of the resources. It is considered + * as a fatal failure since the requirement list may be incomplete + * @since TODO + */ + @Nonnull + public List getResourcesMatchingScript( + @Nonnull SecureGroovyScript script, @CheckForNull Map params) + throws ExecutionException { + List found = new ArrayList<>(); + for (LockableResource r : this.resources) { + if (r.scriptMatches(script, params)) found.add(r); + } + return found; + } + + public LockableResource fromName(String resourceName) { + if (resourceName != null) { + for (LockableResource r : resources) { + if (resourceName.equals(r.getName())) return r; + } + } + return null; + } + + public synchronized boolean queue( + List resources, long queueItemId, String queueProjectName) { + for (LockableResource r : resources) + if (r.isReserved() || r.isQueued(queueItemId) || r.isLocked()) return false; + for (LockableResource r : resources) { + r.setQueued(queueItemId, queueProjectName); + } + return true; + } + + /** + * @deprecated USe {@link + * #tryQueue(org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct, long, + * java.lang.String, int, java.util.Map, java.util.logging.Logger)} + */ + @Deprecated + @CheckForNull + public synchronized List queue( + LockableResourcesStruct requiredResources, + long queueItemId, + String queueItemProject, + int number, // 0 means all + Map params, + Logger log) { + try { + return tryQueue(requiredResources, queueItemId, queueItemProject, number, params, log); + } catch (ExecutionException ex) { + if (LOGGER.isLoggable(Level.WARNING)) { + String itemName = queueItemProject + " (id=" + queueItemId + ")"; + LOGGER.log( + Level.WARNING, + "Failed to queue item " + itemName, + ex.getCause() != null ? ex.getCause() : ex); + } + return null; + } + } + + /** + * Try to acquire the resources required by the task. + * + * @param number Number of resources to acquire. {@code 0} means all + * @return List of the locked resources if the task has been accepted. {@code null} if the item is + * still waiting for the resources + * @throws ExecutionException Cannot queue the resource due to the execution failure. Carries info + * in the cause + * @since TODO + */ + @CheckForNull + public synchronized List tryQueue( + LockableResourcesStruct requiredResources, + long queueItemId, + String queueItemProject, + int number, + Map params, + Logger log) + throws ExecutionException { + List selected = new ArrayList<>(); + + if (!checkCurrentResourcesStatus(selected, queueItemProject, queueItemId, log)) { + // The project has another buildable item waiting -> bail out + log.log( + Level.FINEST, + "{0} has another build waiting resources." + " Waiting for it to proceed first.", + new Object[] {queueItemProject}); + return null; + } + + boolean candidatesByScript = false; + List candidates = new ArrayList<>(); + final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); + if (requiredResources.label != null + && requiredResources.label.isEmpty() + && systemGroovyScript == null) { + candidates = requiredResources.required; + } else if (systemGroovyScript == null) { + candidates = getResourcesWithLabel(requiredResources.label, params); + } else { + candidates = getResourcesMatchingScript(systemGroovyScript, params); + candidatesByScript = true; + } + + for (LockableResource rs : candidates) { + if (number != 0 && (selected.size() >= number)) break; + if (!rs.isReserved() && !rs.isLocked() && !rs.isQueued()) selected.add(rs); + } + + // if did not get wanted amount or did not get all + final int required_amount; + if (candidatesByScript && candidates.isEmpty()) { + /** + * If the groovy script does not return any candidates, it means nothing is needed, even if a + * higher amount is specified. A valid use case is a Matrix job, when not all configurations + * need resources. + */ + required_amount = 0; + } else { + required_amount = number == 0 ? candidates.size() : number; + } + + if (selected.size() != required_amount) { + log.log( + Level.FINEST, + "{0} found {1} resource(s) to queue." + "Waiting for correct amount: {2}.", + new Object[] {queueItemProject, selected.size(), required_amount}); + // just to be sure, clean up + for (LockableResource x : resources) { + if (x.getQueueItemProject() != null && x.getQueueItemProject().equals(queueItemProject)) + x.unqueue(); + } + return null; + } + + for (LockableResource rsc : selected) { + rsc.setQueued(queueItemId, queueItemProject); + } + return selected; + } + + // Adds already selected (in previous queue round) resources to 'selected' + // Return false if another item queued for this project -> bail out + private boolean checkCurrentResourcesStatus( + List selected, String project, long taskId, Logger log) { + for (LockableResource r : resources) { + // This project might already have something in queue + String rProject = r.getQueueItemProject(); + if (rProject != null && rProject.equals(project)) { + if (r.isQueuedByTask(taskId)) { + // this item has queued the resource earlier + selected.add(r); + } else { + // The project has another buildable item waiting -> bail out + log.log( + Level.FINEST, + "{0} has another build " + "that already queued resource {1}. Continue queueing.", + new Object[] {project, r}); + return false; + } + } + } + return true; + } + + public synchronized boolean lock( + Set resources, Run build, @Nullable StepContext context) { + return lock(resources, build, context, null, null, false); + } + + /** Try to lock the resource and return true if locked. */ + public synchronized boolean lock( + Set resources, + Run build, + @Nullable StepContext context, + @Nullable String logmessage, + final String variable, + boolean inversePrecedence) { + boolean needToWait = false; + + for (LockableResource r : resources) { + if (r.isReserved() || r.isLocked()) { + needToWait = true; + break; + } + } + if (!needToWait) { + for (LockableResource r : resources) { + r.unqueue(); + r.setBuild(build); + } + if (context != null) { + // since LockableResource contains transient variables, they cannot be correctly serialized + // hence we use their unique resource names + List resourceNames = new ArrayList<>(); + for (LockableResource resource : resources) { + resourceNames.add(resource.getName()); + } + LockStepExecution.proceed(resourceNames, context, logmessage, variable, inversePrecedence); + } save(); - } - return !needToWait; - } + } + return !needToWait; + } - private synchronized void freeResources(List unlockResourceNames, @Nullable Run build) { - for (String unlockResourceName : unlockResourceNames) { + private synchronized void freeResources( + List unlockResourceNames, @Nullable Run build) { + for (String unlockResourceName : unlockResourceNames) { Iterator resourceIterator = this.resources.iterator(); while (resourceIterator.hasNext()) { LockableResource resource = resourceIterator.next(); if (resource != null - && resource.getName() != null - && resource.getName().equals(unlockResourceName)) { + && resource.getName() != null + && resource.getName().equals(unlockResourceName)) { if (build == null - || (resource.getBuild() != null - && build - .getExternalizableId() - .equals(resource.getBuild().getExternalizableId()))) { - // No more contexts, unlock resource - resource.unqueue(); - resource.setBuild(null); + || (resource.getBuild() != null + && build + .getExternalizableId() + .equals(resource.getBuild().getExternalizableId()))) { + // No more contexts, unlock resource + resource.unqueue(); + resource.setBuild(null); if (resource.isEphemeral()) { resourceIterator.remove(); } - } - } - } - } - } - - public synchronized void unlock(List resourcesToUnLock, @Nullable Run build) { - unlock(resourcesToUnLock, build, null, false); - } - - public synchronized void unlock(@Nullable List resourcesToUnLock, - @Nullable Run build, String requiredVar, boolean inversePrecedence) { - List resourceNamesToUnLock = new ArrayList<>(); - if (resourcesToUnLock != null) { - for (LockableResource r : resourcesToUnLock) { - resourceNamesToUnLock.add(r.getName()); - } - } - - this.unlockNames(resourceNamesToUnLock, build, requiredVar, inversePrecedence); - } - - public synchronized void unlockNames(@Nullable List resourceNamesToUnLock, @Nullable Run build, String requiredVar, boolean inversePrecedence) { - // make sure there is a list of resource names to unlock - if (resourceNamesToUnLock == null || (resourceNamesToUnLock.isEmpty())) { - return; - } - - // process as many contexts as possible - List remainingResourceNamesToUnLock = new ArrayList<>(resourceNamesToUnLock); - - QueuedContextStruct nextContext = null; - while (!remainingResourceNamesToUnLock.isEmpty()) { - // check if there are resources which can be unlocked (and shall not be unlocked) - Set requiredResourceForNextContext = null; - nextContext = this.getNextQueuedContext(remainingResourceNamesToUnLock, inversePrecedence, nextContext); - - // no context is queued which can be started once these resources are free'd. - if (nextContext == null) { - this.freeResources(remainingResourceNamesToUnLock, build); - save(); - return; - } - - requiredResourceForNextContext = checkResourcesAvailability(nextContext.getResources(), null, remainingResourceNamesToUnLock); - - // resourceNamesToUnlock contains the names of the previous resources. - // requiredResourceForNextContext contains the resource objects which are required for the next context. - // It is guaranteed that there is an overlap between the two - the resources which are to be reused. - boolean needToWait = false; - for (LockableResource requiredResource : requiredResourceForNextContext) { - if (!remainingResourceNamesToUnLock.contains(requiredResource.getName())) { - if (requiredResource.isReserved() || requiredResource.isLocked()) { - needToWait = true; - break; - } - } - } - - if (!needToWait) { - // remove context from queue and process it - unqueueContext(nextContext.getContext()); - - List resourceNamesToLock = new ArrayList<>(); - - // lock all (old and new resources) - for (LockableResource requiredResource : requiredResourceForNextContext) { - try { - requiredResource.setBuild(nextContext.getContext().get(Run.class)); - resourceNamesToLock.add(requiredResource.getName()); - } catch (Exception e) { - // skip this context, as the build cannot be retrieved (maybe it was deleted while running?) - LOGGER.log(Level.WARNING, "Skipping queued context for lock. Can not get the Run object from the context to proceed with lock, " + - "this could be a legitimate status if the build waiting for the lock was deleted or" + - " hard killed. More information at Level.FINE if debug is needed."); - LOGGER.log(Level.FINE, "Can not get the Run object from the context to proceed with lock", e); - unlockNames(remainingResourceNamesToUnLock, build, requiredVar, inversePrecedence); - return; - } - } - - // determine old resources no longer needed - List freeResources = new ArrayList<>(); - for (String resourceNameToUnlock : remainingResourceNamesToUnLock) { - boolean resourceStillNeeded = false; - for (LockableResource requiredResource : requiredResourceForNextContext) { - if (resourceNameToUnlock != null && resourceNameToUnlock.equals(requiredResource.getName())) { - resourceStillNeeded = true; - break; - } - } - - if (!resourceStillNeeded) { - freeResources.add(resourceNameToUnlock); - } - } - - // keep unused resources - remainingResourceNamesToUnLock.retainAll(freeResources); - - // continue with next context - LockStepExecution.proceed(resourceNamesToLock, nextContext.getContext(), nextContext.getResourceDescription(), requiredVar, inversePrecedence); - } - } - save(); - } - - /** - * Returns the next queued context with all its requirements satisfied. - * - * @param resourceNamesToUnLock resource names locked at the moment but available is required (as they are going to be unlocked soon - * @param inversePrecedence false pick up context as they are in the queue or true to take the most recent one (satisfying requirements) - * @return the context or null - */ - @CheckForNull - private QueuedContextStruct getNextQueuedContext(List resourceNamesToUnLock, boolean inversePrecedence, QueuedContextStruct from) { - QueuedContextStruct newestEntry = null; - int fromIndex = from != null ? this.queuedContexts.indexOf(from) + 1 : 0; - if (!inversePrecedence) { - for (int i = fromIndex; i < this.queuedContexts.size(); i++) { - QueuedContextStruct entry = this.queuedContexts.get(i); - if (checkResourcesAvailability(entry.getResources(), null, resourceNamesToUnLock) != null) { - return entry; - } - } - } else { - long newest = 0; - List orphan = new ArrayList<>(); - for (int i = fromIndex; i < this.queuedContexts.size(); i++) { - QueuedContextStruct entry = this.queuedContexts.get(i); - if (checkResourcesAvailability(entry.getResources(), null, resourceNamesToUnLock) != null) { - try { - Run run = entry.getContext().get(Run.class); - if (run != null && run.getStartTimeInMillis() > newest) { - newest = run.getStartTimeInMillis(); - newestEntry = entry; - } - } catch (IOException | InterruptedException e) { - // skip this one, for some reason there is no Run object for this context - orphan.add(entry); - } - } - } - if (!orphan.isEmpty()) { - this.queuedContexts.removeAll(orphan); - } - } - - return newestEntry; - } - - /** - * Creates the resource if it does not exist. - */ - public synchronized boolean createResource(String name) { - if (name != null) { - LockableResource existent = fromName(name); - if (existent == null) { + } + } + } + } + } + + public synchronized void unlock( + List resourcesToUnLock, @Nullable Run build) { + unlock(resourcesToUnLock, build, null, false); + } + + public synchronized void unlock( + @Nullable List resourcesToUnLock, + @Nullable Run build, + String requiredVar, + boolean inversePrecedence) { + List resourceNamesToUnLock = new ArrayList<>(); + if (resourcesToUnLock != null) { + for (LockableResource r : resourcesToUnLock) { + resourceNamesToUnLock.add(r.getName()); + } + } + + this.unlockNames(resourceNamesToUnLock, build, requiredVar, inversePrecedence); + } + + public synchronized void unlockNames( + @Nullable List resourceNamesToUnLock, + @Nullable Run build, + String requiredVar, + boolean inversePrecedence) { + // make sure there is a list of resource names to unlock + if (resourceNamesToUnLock == null || (resourceNamesToUnLock.isEmpty())) { + return; + } + + // process as many contexts as possible + List remainingResourceNamesToUnLock = new ArrayList<>(resourceNamesToUnLock); + + QueuedContextStruct nextContext = null; + while (!remainingResourceNamesToUnLock.isEmpty()) { + // check if there are resources which can be unlocked (and shall not be unlocked) + Set requiredResourceForNextContext = null; + nextContext = + this.getNextQueuedContext(remainingResourceNamesToUnLock, inversePrecedence, nextContext); + + // no context is queued which can be started once these resources are free'd. + if (nextContext == null) { + this.freeResources(remainingResourceNamesToUnLock, build); + save(); + return; + } + + requiredResourceForNextContext = + checkResourcesAvailability( + nextContext.getResources(), null, remainingResourceNamesToUnLock); + + // resourceNamesToUnlock contains the names of the previous resources. + // requiredResourceForNextContext contains the resource objects which are required for the + // next context. + // It is guaranteed that there is an overlap between the two - the resources which are to be + // reused. + boolean needToWait = false; + for (LockableResource requiredResource : requiredResourceForNextContext) { + if (!remainingResourceNamesToUnLock.contains(requiredResource.getName())) { + if (requiredResource.isReserved() || requiredResource.isLocked()) { + needToWait = true; + break; + } + } + } + + if (!needToWait) { + // remove context from queue and process it + unqueueContext(nextContext.getContext()); + + List resourceNamesToLock = new ArrayList<>(); + + // lock all (old and new resources) + for (LockableResource requiredResource : requiredResourceForNextContext) { + try { + requiredResource.setBuild(nextContext.getContext().get(Run.class)); + resourceNamesToLock.add(requiredResource.getName()); + } catch (Exception e) { + // skip this context, as the build cannot be retrieved (maybe it was deleted while + // running?) + LOGGER.log( + Level.WARNING, + "Skipping queued context for lock. Can not get the Run object from the context to proceed with lock, " + + "this could be a legitimate status if the build waiting for the lock was deleted or" + + " hard killed. More information at Level.FINE if debug is needed."); + LOGGER.log( + Level.FINE, "Can not get the Run object from the context to proceed with lock", e); + unlockNames(remainingResourceNamesToUnLock, build, requiredVar, inversePrecedence); + return; + } + } + + // determine old resources no longer needed + List freeResources = new ArrayList<>(); + for (String resourceNameToUnlock : remainingResourceNamesToUnLock) { + boolean resourceStillNeeded = false; + for (LockableResource requiredResource : requiredResourceForNextContext) { + if (resourceNameToUnlock != null + && resourceNameToUnlock.equals(requiredResource.getName())) { + resourceStillNeeded = true; + break; + } + } + + if (!resourceStillNeeded) { + freeResources.add(resourceNameToUnlock); + } + } + + // keep unused resources + remainingResourceNamesToUnLock.retainAll(freeResources); + + // continue with next context + LockStepExecution.proceed( + resourceNamesToLock, + nextContext.getContext(), + nextContext.getResourceDescription(), + requiredVar, + inversePrecedence); + } + } + save(); + } + + /** + * Returns the next queued context with all its requirements satisfied. + * + * @param resourceNamesToUnLock resource names locked at the moment but available is required (as + * they are going to be unlocked soon + * @param inversePrecedence false pick up context as they are in the queue or true to take the + * most recent one (satisfying requirements) + * @return the context or null + */ + @CheckForNull + private QueuedContextStruct getNextQueuedContext( + List resourceNamesToUnLock, boolean inversePrecedence, QueuedContextStruct from) { + QueuedContextStruct newestEntry = null; + int fromIndex = from != null ? this.queuedContexts.indexOf(from) + 1 : 0; + if (!inversePrecedence) { + for (int i = fromIndex; i < this.queuedContexts.size(); i++) { + QueuedContextStruct entry = this.queuedContexts.get(i); + if (checkResourcesAvailability(entry.getResources(), null, resourceNamesToUnLock) != null) { + return entry; + } + } + } else { + long newest = 0; + List orphan = new ArrayList<>(); + for (int i = fromIndex; i < this.queuedContexts.size(); i++) { + QueuedContextStruct entry = this.queuedContexts.get(i); + if (checkResourcesAvailability(entry.getResources(), null, resourceNamesToUnLock) != null) { + try { + Run run = entry.getContext().get(Run.class); + if (run != null && run.getStartTimeInMillis() > newest) { + newest = run.getStartTimeInMillis(); + newestEntry = entry; + } + } catch (IOException | InterruptedException e) { + // skip this one, for some reason there is no Run object for this context + orphan.add(entry); + } + } + } + if (!orphan.isEmpty()) { + this.queuedContexts.removeAll(orphan); + } + } + + return newestEntry; + } + + /** Creates the resource if it does not exist. */ + public synchronized boolean createResource(String name) { + if (name != null) { + LockableResource existent = fromName(name); + if (existent == null) { LockableResource resource = new LockableResource(name); resource.setEphemeral(true); getResources().add(resource); - save(); - return true; - } - } - return false; - } - - public synchronized boolean createResourceWithLabel(String name, String label) { - if (name !=null && label !=null) { - LockableResource existent = fromName(name); - if (existent == null) { - getResources().add(new LockableResource(name, "", label, null)); - save(); - return true; - } - } - return false; - } - - public synchronized boolean reserve(List resources, - String userName) { - for (LockableResource r : resources) { - if (r.isReserved() || r.isLocked() || r.isQueued()) { - return false; - } - } - for (LockableResource r : resources) { - r.setReservedBy(userName); - } - save(); - return true; - } - - private void unreserveResources(@Nonnull List resources) { - for (LockableResource l : resources) { - l.unReserve(); - } - save(); - } - public synchronized void unreserve(List resources) { - // make sure there is a list of resources to unreserve - if (resources == null || (resources.isEmpty())) { - return; - } - List resourceNamesToUnreserve = new ArrayList<>(); - for (LockableResource r : resources) { - resourceNamesToUnreserve.add(r.getName()); - } - - // check if there are resources which can be unlocked (and shall not be unlocked) - Set requiredResourceForNextContext = null; - QueuedContextStruct nextContext = this.getNextQueuedContext(resourceNamesToUnreserve, false, null); - - // no context is queued which can be started once these resources are free'd. - if (nextContext == null) { - LOGGER.log(Level.FINER, "No context queued for resources " + StringUtils.join(resourceNamesToUnreserve, ", ") + " so unreserving and proceeding."); - unreserveResources(resources); - return; - } - - PrintStream nextContextLogger = null; - try { - TaskListener nextContextTaskListener = nextContext.getContext().get(TaskListener.class); - if (nextContextTaskListener != null) { - nextContextLogger = nextContextTaskListener.getLogger(); - } - } catch (IOException | InterruptedException e) { - LOGGER.log(Level.FINE, "Could not get logger for next context: " + e, e); - } - - // remove context from queue and process it - requiredResourceForNextContext = checkResourcesAvailability(nextContext.getResources(), - nextContextLogger, - resourceNamesToUnreserve); - this.queuedContexts.remove(nextContext); - - // resourceNamesToUnreserve contains the names of the previous resources. - // requiredResourceForNextContext contains the resource objects which are required for the next context. - // It is guaranteed that there is an overlap between the two - the resources which are to be reused. - boolean needToWait = false; - for (LockableResource requiredResource : requiredResourceForNextContext) { - if (!resourceNamesToUnreserve.contains(requiredResource.getName())) { - if (requiredResource.isReserved() || requiredResource.isLocked()) { - needToWait = true; - break; - } - } - } - - if (needToWait) { - unreserveResources(resources); - return; - } else { - unreserveResources(resources); - List resourceNamesToLock = new ArrayList<>(); - - // lock all (old and new resources) - for (LockableResource requiredResource : requiredResourceForNextContext) { - try { - requiredResource.setBuild(nextContext.getContext().get(Run.class)); - resourceNamesToLock.add(requiredResource.getName()); - } catch (Exception e) { - // skip this context, as the build cannot be retrieved (maybe it was deleted while running?) - LOGGER.log(Level.WARNING, "Skipping queued context for lock. Can not get the Run object from the context to proceed with lock, " + - "this could be a legitimate status if the build waiting for the lock was deleted or" + - " hard killed. More information at Level.FINE if debug is needed."); - LOGGER.log(Level.FINE, "Can not get the Run object from the context to proceed with lock", e); - return; - } - } - - // continue with next context - LockStepExecution.proceed(resourceNamesToLock, nextContext.getContext(), nextContext.getResourceDescription(), null, false); - } - save(); - } - - @Override - public String getDisplayName() { - return "External Resources"; - } - - public synchronized void reset(List resources) { - for (LockableResource r : resources) { - r.reset(); - } - save(); - } + save(); + return true; + } + } + return false; + } + + public synchronized boolean createResourceWithLabel(String name, String label) { + if (name != null && label != null) { + LockableResource existent = fromName(name); + if (existent == null) { + getResources().add(new LockableResource(name, "", label, null)); + save(); + return true; + } + } + return false; + } + + public synchronized boolean reserve(List resources, String userName) { + for (LockableResource r : resources) { + if (r.isReserved() || r.isLocked() || r.isQueued()) { + return false; + } + } + for (LockableResource r : resources) { + r.setReservedBy(userName); + } + save(); + return true; + } + + private void unreserveResources(@Nonnull List resources) { + for (LockableResource l : resources) { + l.unReserve(); + } + save(); + } + + public synchronized void unreserve(List resources) { + // make sure there is a list of resources to unreserve + if (resources == null || (resources.isEmpty())) { + return; + } + List resourceNamesToUnreserve = new ArrayList<>(); + for (LockableResource r : resources) { + resourceNamesToUnreserve.add(r.getName()); + } + + // check if there are resources which can be unlocked (and shall not be unlocked) + Set requiredResourceForNextContext = null; + QueuedContextStruct nextContext = + this.getNextQueuedContext(resourceNamesToUnreserve, false, null); + + // no context is queued which can be started once these resources are free'd. + if (nextContext == null) { + LOGGER.log( + Level.FINER, + "No context queued for resources " + + StringUtils.join(resourceNamesToUnreserve, ", ") + + " so unreserving and proceeding."); + unreserveResources(resources); + return; + } + + PrintStream nextContextLogger = null; + try { + TaskListener nextContextTaskListener = nextContext.getContext().get(TaskListener.class); + if (nextContextTaskListener != null) { + nextContextLogger = nextContextTaskListener.getLogger(); + } + } catch (IOException | InterruptedException e) { + LOGGER.log(Level.FINE, "Could not get logger for next context: " + e, e); + } + + // remove context from queue and process it + requiredResourceForNextContext = + checkResourcesAvailability( + nextContext.getResources(), nextContextLogger, resourceNamesToUnreserve); + this.queuedContexts.remove(nextContext); + + // resourceNamesToUnreserve contains the names of the previous resources. + // requiredResourceForNextContext contains the resource objects which are required for the next + // context. + // It is guaranteed that there is an overlap between the two - the resources which are to be + // reused. + boolean needToWait = false; + for (LockableResource requiredResource : requiredResourceForNextContext) { + if (!resourceNamesToUnreserve.contains(requiredResource.getName())) { + if (requiredResource.isReserved() || requiredResource.isLocked()) { + needToWait = true; + break; + } + } + } + + if (needToWait) { + unreserveResources(resources); + return; + } else { + unreserveResources(resources); + List resourceNamesToLock = new ArrayList<>(); + + // lock all (old and new resources) + for (LockableResource requiredResource : requiredResourceForNextContext) { + try { + requiredResource.setBuild(nextContext.getContext().get(Run.class)); + resourceNamesToLock.add(requiredResource.getName()); + } catch (Exception e) { + // skip this context, as the build cannot be retrieved (maybe it was deleted while + // running?) + LOGGER.log( + Level.WARNING, + "Skipping queued context for lock. Can not get the Run object from the context to proceed with lock, " + + "this could be a legitimate status if the build waiting for the lock was deleted or" + + " hard killed. More information at Level.FINE if debug is needed."); + LOGGER.log( + Level.FINE, "Can not get the Run object from the context to proceed with lock", e); + return; + } + } + + // continue with next context + LockStepExecution.proceed( + resourceNamesToLock, + nextContext.getContext(), + nextContext.getResourceDescription(), + null, + false); + } + save(); + } + + @Override + public String getDisplayName() { + return "External Resources"; + } + + public synchronized void reset(List resources) { + for (LockableResource r : resources) { + r.reset(); + } + save(); + } @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { @@ -687,163 +727,174 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti bc.commit(); } catch (IOException exception) { LOGGER.log( - Level.WARNING, "Exception occurred while committing bulkchange operation.", exception); + Level.WARNING, "Exception occurred while committing bulkchange operation.", exception); return false; } return true; } - /** - * Checks if there are enough resources available to satisfy the requirements specified - * within requiredResources and returns the necessary available resources. - * If not enough resources are available, returns null. - */ - public synchronized Set checkResourcesAvailability(List requiredResourcesList, - @Nullable PrintStream logger, @Nullable List lockedResourcesAboutToBeUnlocked) { - - List requiredResourcesCandidatesList = new ArrayList<>(); - - // Build possible resources for each requirement - for (LockableResourcesStruct requiredResources : requiredResourcesList) { - // get possible resources - int requiredAmount = 0; // 0 means all - List candidates = new ArrayList<>(); - if (requiredResources.label != null && requiredResources.label.isEmpty()) { - candidates.addAll(requiredResources.required); - } else { - candidates.addAll(getResourcesWithLabel(requiredResources.label, null)); - if (requiredResources.requiredNumber != null) { - try { - requiredAmount = Integer.parseInt(requiredResources.requiredNumber); - } catch (NumberFormatException e) { - requiredAmount = 0; - } - } - } - - if (requiredAmount == 0) { - requiredAmount = candidates.size(); - } - - requiredResourcesCandidatesList.add(new LockableResourcesCandidatesStruct(candidates, requiredAmount)); - } - - // Process freed resources - int totalSelected = 0; - - for (LockableResourcesCandidatesStruct requiredResources : requiredResourcesCandidatesList) { - // start with an empty set of selected resources - List selected = new ArrayList<>(); - - // some resources might be already locked, but will be freed. - // Determine if these resources can be reused - if (lockedResourcesAboutToBeUnlocked != null) { - for (LockableResource candidate : requiredResources.candidates) { - if (selected.size() >= requiredResources.requiredAmount) { - break; - } - if (lockedResourcesAboutToBeUnlocked.contains(candidate.getName())) { - selected.add(candidate); - } - } - } - - totalSelected += selected.size(); - requiredResources.selected = selected; - } - - // if none of the currently locked resources can be reused, - // this context is not suitable to be continued with - if (lockedResourcesAboutToBeUnlocked != null && totalSelected == 0) { - return null; - } - - // Find remaining resources - Set allSelected = new HashSet<>(); - - for (LockableResourcesCandidatesStruct requiredResources : requiredResourcesCandidatesList) { - List candidates = requiredResources.candidates; - List selected = requiredResources.selected; - int requiredAmount = requiredResources.requiredAmount; - - // Try and re-use as many previously selected resources first - List alreadySelectedCandidates = new ArrayList<>(candidates); - alreadySelectedCandidates.retainAll(allSelected); - for (LockableResource rs : alreadySelectedCandidates) { - if (selected.size() >= requiredAmount) { - break; - } - if (!rs.isReserved() && !rs.isLocked()) { - selected.add(rs); - } - } - - candidates.removeAll(alreadySelectedCandidates); - for (LockableResource rs : candidates) { - if (selected.size() >= requiredAmount) { - break; - } - if (!rs.isReserved() && !rs.isLocked()) { - selected.add(rs); - } - } - - if (selected.size() < requiredAmount) { - if (logger != null) { - logger.println("Found " + selected.size() + " available resource(s). Waiting for correct amount: " + requiredAmount + "."); - } - return null; - } - - allSelected.addAll(selected); - } - - return allSelected; - } - - /* - * Adds the given context and the required resources to the queue if - * this context is not yet queued. - */ - public synchronized void queueContext(StepContext context, List requiredResources, String resourceDescription) { - for (QueuedContextStruct entry : this.queuedContexts) { - if (entry.getContext() == context) { - return; - } - } - - this.queuedContexts.add(new QueuedContextStruct(context, requiredResources, resourceDescription)); - save(); - } - - public synchronized boolean unqueueContext(StepContext context) { - for (Iterator iter = this.queuedContexts.listIterator(); iter.hasNext(); ) { - if (iter.next().getContext() == context) { - iter.remove(); - save(); - return true; - } - } - return false; - } - - public static LockableResourcesManager get() { - return (LockableResourcesManager) Jenkins.getInstance() - .getDescriptorOrDie(LockableResourcesManager.class); - } - - @Override - public synchronized void save() { - if(BulkChange.contains(this)) - return; - - try { - getConfigFile().write(this); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Failed to save " + getConfigFile(),e); - } + /** + * Checks if there are enough resources available to satisfy the requirements specified within + * requiredResources and returns the necessary available resources. If not enough resources are + * available, returns null. + */ + public synchronized Set checkResourcesAvailability( + List requiredResourcesList, + @Nullable PrintStream logger, + @Nullable List lockedResourcesAboutToBeUnlocked) { + + List requiredResourcesCandidatesList = new ArrayList<>(); + + // Build possible resources for each requirement + for (LockableResourcesStruct requiredResources : requiredResourcesList) { + // get possible resources + int requiredAmount = 0; // 0 means all + List candidates = new ArrayList<>(); + if (requiredResources.label != null && requiredResources.label.isEmpty()) { + candidates.addAll(requiredResources.required); + } else { + candidates.addAll(getResourcesWithLabel(requiredResources.label, null)); + if (requiredResources.requiredNumber != null) { + try { + requiredAmount = Integer.parseInt(requiredResources.requiredNumber); + } catch (NumberFormatException e) { + requiredAmount = 0; + } + } + } + + if (requiredAmount == 0) { + requiredAmount = candidates.size(); + } + + requiredResourcesCandidatesList.add( + new LockableResourcesCandidatesStruct(candidates, requiredAmount)); + } + + // Process freed resources + int totalSelected = 0; + + for (LockableResourcesCandidatesStruct requiredResources : requiredResourcesCandidatesList) { + // start with an empty set of selected resources + List selected = new ArrayList<>(); + + // some resources might be already locked, but will be freed. + // Determine if these resources can be reused + if (lockedResourcesAboutToBeUnlocked != null) { + for (LockableResource candidate : requiredResources.candidates) { + if (selected.size() >= requiredResources.requiredAmount) { + break; + } + if (lockedResourcesAboutToBeUnlocked.contains(candidate.getName())) { + selected.add(candidate); + } + } + } + + totalSelected += selected.size(); + requiredResources.selected = selected; + } + + // if none of the currently locked resources can be reused, + // this context is not suitable to be continued with + if (lockedResourcesAboutToBeUnlocked != null && totalSelected == 0) { + return null; + } + + // Find remaining resources + Set allSelected = new HashSet<>(); + + for (LockableResourcesCandidatesStruct requiredResources : requiredResourcesCandidatesList) { + List candidates = requiredResources.candidates; + List selected = requiredResources.selected; + int requiredAmount = requiredResources.requiredAmount; + + // Try and re-use as many previously selected resources first + List alreadySelectedCandidates = new ArrayList<>(candidates); + alreadySelectedCandidates.retainAll(allSelected); + for (LockableResource rs : alreadySelectedCandidates) { + if (selected.size() >= requiredAmount) { + break; + } + if (!rs.isReserved() && !rs.isLocked()) { + selected.add(rs); } + } - private static final Logger LOGGER = Logger.getLogger(LockableResourcesManager.class.getName()); + candidates.removeAll(alreadySelectedCandidates); + for (LockableResource rs : candidates) { + if (selected.size() >= requiredAmount) { + break; + } + if (!rs.isReserved() && !rs.isLocked()) { + selected.add(rs); + } + } + + if (selected.size() < requiredAmount) { + if (logger != null) { + logger.println( + "Found " + + selected.size() + + " available resource(s). Waiting for correct amount: " + + requiredAmount + + "."); + } + return null; + } + + allSelected.addAll(selected); + } + + return allSelected; + } + + /* + * Adds the given context and the required resources to the queue if + * this context is not yet queued. + */ + public synchronized void queueContext( + StepContext context, + List requiredResources, + String resourceDescription) { + for (QueuedContextStruct entry : this.queuedContexts) { + if (entry.getContext() == context) { + return; + } + } + + this.queuedContexts.add( + new QueuedContextStruct(context, requiredResources, resourceDescription)); + save(); + } + + public synchronized boolean unqueueContext(StepContext context) { + for (Iterator iter = this.queuedContexts.listIterator(); + iter.hasNext(); ) { + if (iter.next().getContext() == context) { + iter.remove(); + save(); + return true; + } + } + return false; + } + + public static LockableResourcesManager get() { + return (LockableResourcesManager) + Jenkins.getInstance().getDescriptorOrDie(LockableResourcesManager.class); + } + + @Override + public synchronized void save() { + if (BulkChange.contains(this)) return; + + try { + getConfigFile().write(this); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Failed to save " + getConfigFile(), e); + } + } + private static final Logger LOGGER = Logger.getLogger(LockableResourcesManager.class.getName()); } From de7e72a2810999c02d3db85e4e8b92dd531138b1 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 11 Oct 2019 00:01:05 +0200 Subject: [PATCH 0044/1078] Cleanup and format all tests --- .../BasicIntegrationTest.java | 431 ++++++++++-------- .../LockStepHardKillTest.java | 3 +- .../LockStepWithRestartTest.java | 9 +- ...LockableResourceRootActionSEC1361Test.java | 110 ++--- .../LockableResourceTest.java | 328 +++---------- 5 files changed, 351 insertions(+), 530 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java b/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java index 126f3632b..5cc35dde4 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java @@ -1,17 +1,28 @@ package org.jenkins.plugins.lockableresources; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; import hudson.model.Item; import hudson.model.Queue; +import hudson.model.Result; import hudson.model.User; import hudson.model.queue.QueueTaskFuture; import hudson.security.ACL; import hudson.triggers.TimerTrigger; import hudson.util.FormValidation; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; import jenkins.model.Jenkins; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; @@ -29,201 +40,223 @@ import org.jvnet.hudson.test.SleepBuilder; import org.jvnet.hudson.test.TestExtension; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.FreeStyleBuild; -import hudson.model.FreeStyleProject; -import hudson.model.Result; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - public class BasicIntegrationTest { - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Test - @Issue("JENKINS-34853") - public void security170fix() throws Exception { - LockableResourcesManager.get().createResource("resource1"); - FreeStyleProject p = j.createFreeStyleProject("p"); - p.addProperty(new RequiredResourcesProperty("resource1", "resourceNameVar", null, null)); - p.getBuildersList().add(new PrinterBuilder()); - - FreeStyleBuild b1 = p.scheduleBuild2(0).get(); - j.assertLogContains("resourceNameVar: resource1", b1); - j.assertBuildStatus(Result.SUCCESS, b1); - } - - @Test - public void migrateToScript() throws Exception { - LockableResourcesManager.get().createResource("resource1"); - - FreeStyleProject p = j.createFreeStyleProject("p"); - p.addProperty(new RequiredResourcesProperty(null, null, null, "groovy:resourceName == 'resource1'", null)); - - p.save(); - - j.jenkins.reload(); - - FreeStyleProject p2 = j.jenkins.getItemByFullName("p", FreeStyleProject.class); - RequiredResourcesProperty newProp = p2.getProperty(RequiredResourcesProperty.class); - assertNull(newProp.getLabelName()); - assertNotNull(newProp.getResourceMatchScript()); - assertEquals("resourceName == 'resource1'", newProp.getResourceMatchScript().getScript()); - - p2.getBuildersList().add(new SleepBuilder(5000)); - - FreeStyleProject p3 = j.createFreeStyleProject("p3"); - p3.addProperty(new RequiredResourcesProperty("resource1", null, "1", null, null)); - p3.getBuildersList().add(new SleepBuilder(10000)); - - final QueueTaskFuture taskA = p3.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); - Thread.sleep(2500); - final QueueTaskFuture taskB = p2.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); - - final FreeStyleBuild buildA = taskA.get(60, TimeUnit.SECONDS); - final FreeStyleBuild buildB = taskB.get(60, TimeUnit.SECONDS); - - long buildAEndTime = buildA.getStartTimeInMillis() + buildA.getDuration(); - assertTrue("Project A build should be finished before the build of project B starts. " + - "A finished at " + buildAEndTime + ", B started at " + buildB.getStartTimeInMillis(), - buildB.getStartTimeInMillis() >= buildAEndTime); - } - - @Test - public void configRoundTrip() throws Exception { - LockableResourcesManager.get().createResource("resource1"); - - FreeStyleProject withResource = j.createFreeStyleProject("withResource"); - withResource.addProperty(new RequiredResourcesProperty("resource1", "resourceNameVar", null, null, null)); - FreeStyleProject withResourceRoundTrip = j.configRoundtrip(withResource); - - RequiredResourcesProperty withResourceProp = withResourceRoundTrip.getProperty(RequiredResourcesProperty.class); - assertNotNull(withResourceProp); - assertEquals("resource1", withResourceProp.getResourceNames()); - assertEquals("resourceNameVar", withResourceProp.getResourceNamesVar()); - assertNull(withResourceProp.getResourceNumber()); - assertNull(withResourceProp.getLabelName()); - assertNull(withResourceProp.getResourceMatchScript()); - - FreeStyleProject withLabel = j.createFreeStyleProject("withLabel"); - withLabel.addProperty(new RequiredResourcesProperty(null, null, null, "some-label", null)); - FreeStyleProject withLabelRoundTrip = j.configRoundtrip(withLabel); - - RequiredResourcesProperty withLabelProp = withLabelRoundTrip.getProperty(RequiredResourcesProperty.class); - assertNotNull(withLabelProp); - assertNull(withLabelProp.getResourceNames()); - assertNull(withLabelProp.getResourceNamesVar()); - assertNull(withLabelProp.getResourceNumber()); - assertEquals("some-label", withLabelProp.getLabelName()); - assertNull(withLabelProp.getResourceMatchScript()); - - FreeStyleProject withScript = j.createFreeStyleProject("withScript"); - SecureGroovyScript origScript = new SecureGroovyScript("return true", false, null); - withScript.addProperty(new RequiredResourcesProperty(null, null, null, null, origScript)); - FreeStyleProject withScriptRoundTrip = j.configRoundtrip(withScript); - - RequiredResourcesProperty withScriptProp = withScriptRoundTrip.getProperty(RequiredResourcesProperty.class); - assertNotNull(withScriptProp); - assertNull(withScriptProp.getResourceNames()); - assertNull(withScriptProp.getResourceNamesVar()); - assertNull(withScriptProp.getResourceNumber()); - assertNull(withScriptProp.getLabelName()); - assertNotNull(withScriptProp.getResourceMatchScript()); - assertEquals("return true", withScriptProp.getResourceMatchScript().getScript()); - assertEquals(false, withScriptProp.getResourceMatchScript().isSandbox()); - } - - @Test - public void validationFailure() throws Exception { - RequiredResourcesProperty.DescriptorImpl d = new RequiredResourcesProperty.DescriptorImpl(); - LockableResourcesManager.get().createResource("resource1"); - LockableResource r = LockableResourcesManager.get().getResources().get(0); - r.setLabels("some-label"); - - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckResourceNames("resource1", null, true).getMessage()); - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckResourceNames("resource1", "some-label", false).getMessage()); - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckResourceNames("resource1", "some-label", true).getMessage()); - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckLabelName("some-label", "resource1", false).getMessage()); - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckLabelName("some-label", null, true).getMessage()); - assertEquals("Only label, groovy expression, or resources can be defined, not more than one.", d.doCheckLabelName("some-label", "resource1", true).getMessage()); - - assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false)); - assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false)); - } - - @TestExtension - public static class PrinterBuilder extends MockBuilder { - - public PrinterBuilder() { - super(Result.SUCCESS); - } - - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - listener.getLogger().println("resourceNameVar: " + build.getEnvironment(listener).get("resourceNameVar")); - return true; - } - - } - - @Test - public void approvalRequired() throws Exception { - LockableResourcesManager.get().createResource(LockableResourcesRootAction.ICON); - - j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); - - j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() - .grant(Jenkins.READ, Item.READ).everywhere().toAuthenticated() - .grant(Jenkins.ADMINISTER).everywhere().to("bob") - .grant(Item.CONFIGURE, Item.BUILD).everywhere().to("alice")); - - final String SCRIPT = "resourceName == org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction.ICON;"; - - FreeStyleProject p = j.createFreeStyleProject(); - SecurityContext orig = ACL.impersonate(User.get("alice").impersonate()); - SecurityContextHolder.setContext(orig); - SecureGroovyScript groovyScript = new SecureGroovyScript(SCRIPT, true, null).configuring(ApprovalContext.create()); - - p.addProperty(new RequiredResourcesProperty(null, null, null, null, groovyScript)); - - JenkinsRule.WebClient wc = j.createWebClient(); - wc.login("alice"); - - QueueTaskFuture futureBuild = p.scheduleBuild2(0); - - // Sleeping briefly to make sure the queue gets updated. - Thread.sleep(2000); - - List items = j.jenkins.getQueue().getItems(p); - assertNotNull(items); - assertEquals(1, items.size()); - - assertTrue(items.get(0) instanceof Queue.BlockedItem); - - Queue.BlockedItem blockedItem = (Queue.BlockedItem) items.get(0); - assertTrue(blockedItem.getCauseOfBlockage() instanceof LockableResourcesQueueTaskDispatcher.BecauseResourcesQueueFailed); - - ScriptApproval approval = ScriptApproval.get(); - List pending = new ArrayList<>(); - pending.addAll(approval.getPendingSignatures()); - - assertFalse(pending.isEmpty()); - assertEquals(1, pending.size()); - ScriptApproval.PendingSignature firstPending = pending.get(0); - - assertEquals("staticField org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction ICON", - firstPending.signature); - approval.approveSignature(firstPending.signature); - - j.assertBuildStatusSuccess(futureBuild); - } - - + @Rule public JenkinsRule j = new JenkinsRule(); + + @Test + @Issue("JENKINS-34853") + public void security170fix() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + FreeStyleProject p = j.createFreeStyleProject("p"); + p.addProperty(new RequiredResourcesProperty("resource1", "resourceNameVar", null, null, null)); + p.getBuildersList().add(new PrinterBuilder()); + + FreeStyleBuild b1 = p.scheduleBuild2(0).get(); + j.assertLogContains("resourceNameVar: resource1", b1); + j.assertBuildStatus(Result.SUCCESS, b1); + } + + @Test + public void migrateToScript() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + + FreeStyleProject p = j.createFreeStyleProject("p"); + p.addProperty( + new RequiredResourcesProperty( + null, null, null, "groovy:resourceName == 'resource1'", null)); + + p.save(); + + j.jenkins.reload(); + + FreeStyleProject p2 = j.jenkins.getItemByFullName("p", FreeStyleProject.class); + RequiredResourcesProperty newProp = p2.getProperty(RequiredResourcesProperty.class); + assertNull(newProp.getLabelName()); + assertNotNull(newProp.getResourceMatchScript()); + assertEquals("resourceName == 'resource1'", newProp.getResourceMatchScript().getScript()); + + p2.getBuildersList().add(new SleepBuilder(5000)); + + FreeStyleProject p3 = j.createFreeStyleProject("p3"); + p3.addProperty(new RequiredResourcesProperty("resource1", null, "1", null, null)); + p3.getBuildersList().add(new SleepBuilder(10000)); + + final QueueTaskFuture taskA = + p3.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); + Thread.sleep(2500); + final QueueTaskFuture taskB = + p2.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); + + final FreeStyleBuild buildA = taskA.get(60, TimeUnit.SECONDS); + final FreeStyleBuild buildB = taskB.get(60, TimeUnit.SECONDS); + + long buildAEndTime = buildA.getStartTimeInMillis() + buildA.getDuration(); + assertTrue( + "Project A build should be finished before the build of project B starts. " + + "A finished at " + + buildAEndTime + + ", B started at " + + buildB.getStartTimeInMillis(), + buildB.getStartTimeInMillis() >= buildAEndTime); + } + + @Test + public void configRoundTrip() throws Exception { + LockableResourcesManager.get().createResource("resource1"); + + FreeStyleProject withResource = j.createFreeStyleProject("withResource"); + withResource.addProperty( + new RequiredResourcesProperty("resource1", "resourceNameVar", null, null, null)); + FreeStyleProject withResourceRoundTrip = j.configRoundtrip(withResource); + + RequiredResourcesProperty withResourceProp = + withResourceRoundTrip.getProperty(RequiredResourcesProperty.class); + assertNotNull(withResourceProp); + assertEquals("resource1", withResourceProp.getResourceNames()); + assertEquals("resourceNameVar", withResourceProp.getResourceNamesVar()); + assertNull(withResourceProp.getResourceNumber()); + assertNull(withResourceProp.getLabelName()); + assertNull(withResourceProp.getResourceMatchScript()); + + FreeStyleProject withLabel = j.createFreeStyleProject("withLabel"); + withLabel.addProperty(new RequiredResourcesProperty(null, null, null, "some-label", null)); + FreeStyleProject withLabelRoundTrip = j.configRoundtrip(withLabel); + + RequiredResourcesProperty withLabelProp = + withLabelRoundTrip.getProperty(RequiredResourcesProperty.class); + assertNotNull(withLabelProp); + assertNull(withLabelProp.getResourceNames()); + assertNull(withLabelProp.getResourceNamesVar()); + assertNull(withLabelProp.getResourceNumber()); + assertEquals("some-label", withLabelProp.getLabelName()); + assertNull(withLabelProp.getResourceMatchScript()); + + FreeStyleProject withScript = j.createFreeStyleProject("withScript"); + SecureGroovyScript origScript = new SecureGroovyScript("return true", false, null); + withScript.addProperty(new RequiredResourcesProperty(null, null, null, null, origScript)); + FreeStyleProject withScriptRoundTrip = j.configRoundtrip(withScript); + + RequiredResourcesProperty withScriptProp = + withScriptRoundTrip.getProperty(RequiredResourcesProperty.class); + assertNotNull(withScriptProp); + assertNull(withScriptProp.getResourceNames()); + assertNull(withScriptProp.getResourceNamesVar()); + assertNull(withScriptProp.getResourceNumber()); + assertNull(withScriptProp.getLabelName()); + assertNotNull(withScriptProp.getResourceMatchScript()); + assertEquals("return true", withScriptProp.getResourceMatchScript().getScript()); + assertEquals(false, withScriptProp.getResourceMatchScript().isSandbox()); + } + + @Test + public void validationFailure() throws Exception { + RequiredResourcesProperty.DescriptorImpl d = new RequiredResourcesProperty.DescriptorImpl(); + LockableResourcesManager.get().createResource("resource1"); + LockableResource r = LockableResourcesManager.get().getResources().get(0); + r.setLabels("some-label"); + + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", null, true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", "some-label", false).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", "some-label", true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", "resource1", false).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", null, true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", "resource1", true).getMessage()); + + assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false)); + assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false)); + } + + @Test + public void approvalRequired() throws Exception { + LockableResourcesManager.get().createResource(LockableResourcesRootAction.ICON); + + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + + j.jenkins.setAuthorizationStrategy( + new MockAuthorizationStrategy() + .grant(Jenkins.READ, Item.READ) + .everywhere() + .toAuthenticated() + .grant(Jenkins.ADMINISTER) + .everywhere() + .to("bob") + .grant(Item.CONFIGURE, Item.BUILD) + .everywhere() + .to("alice")); + + final String SCRIPT = + "resourceName == org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction.ICON;"; + + FreeStyleProject p = j.createFreeStyleProject(); + SecurityContext orig = ACL.impersonate(User.get("alice").impersonate()); + SecurityContextHolder.setContext(orig); + SecureGroovyScript groovyScript = + new SecureGroovyScript(SCRIPT, true, null).configuring(ApprovalContext.create()); + + p.addProperty(new RequiredResourcesProperty(null, null, null, null, groovyScript)); + + JenkinsRule.WebClient wc = j.createWebClient(); + wc.login("alice"); + + QueueTaskFuture futureBuild = p.scheduleBuild2(0); + + // Sleeping briefly to make sure the queue gets updated. + Thread.sleep(2000); + + List items = j.jenkins.getQueue().getItems(p); + assertNotNull(items); + assertEquals(1, items.size()); + + assertTrue(items.get(0) instanceof Queue.BlockedItem); + + Queue.BlockedItem blockedItem = (Queue.BlockedItem) items.get(0); + assertTrue( + blockedItem.getCauseOfBlockage() + instanceof LockableResourcesQueueTaskDispatcher.BecauseResourcesQueueFailed); + + ScriptApproval approval = ScriptApproval.get(); + List pending = new ArrayList<>(); + pending.addAll(approval.getPendingSignatures()); + + assertFalse(pending.isEmpty()); + assertEquals(1, pending.size()); + ScriptApproval.PendingSignature firstPending = pending.get(0); + + assertEquals( + "staticField org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction ICON", + firstPending.signature); + approval.approveSignature(firstPending.signature); + + j.assertBuildStatusSuccess(futureBuild); + } + + @TestExtension + public static class PrinterBuilder extends MockBuilder { + + public PrinterBuilder() { + super(Result.SUCCESS); + } + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { + listener + .getLogger() + .println("resourceNameVar: " + build.getEnvironment(listener).get("resourceNameVar")); + return true; + } + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index 02dc915c8..fb700aa61 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -86,7 +86,8 @@ public void hardKillWithWaitingRuns() throws Exception { for (int i = 0; i < 3; i++) { WorkflowRun rNext = p.scheduleBuild2(0).waitForStart(); if (prevBuild != null) { - j.waitForMessage("[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); + j.waitForMessage( + "[resource1] is locked by " + prevBuild.getFullDisplayName() + ", waiting...", rNext); isPaused(rNext, 1, 1); interruptTermKill(prevBuild); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index bae553521..38491e276 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -41,12 +41,14 @@ public void lockOrderRestart() { SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); // Ensure that b2 reaches the lock before b3 - j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); + j.waitForMessage( + "[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); WorkflowRun b3 = p.scheduleBuild2(0).waitForStart(); // Both 2 and 3 are waiting for locking resource1 - j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); + j.waitForMessage( + "[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); }); @@ -64,7 +66,8 @@ public void lockOrderRestart() { j.waitForMessage("Lock acquired on [resource1]", b2); isPaused(b2, 1, 0); - j.assertLogContains("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); + j.assertLogContains( + "[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); SemaphoreStep.success("wait-inside/2", null); SemaphoreStep.waitForStart("wait-inside/3", b3); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java index 659951167..4e4f73905 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java @@ -43,61 +43,61 @@ import org.jvnet.hudson.test.JenkinsRule; public class LockableResourceRootActionSEC1361Test { - - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Test - public void regularCase() throws Exception { - checkXssWithResourceName("resource1"); - } - - @Test - @Issue("SECURITY-1361") - public void noXssOnClick() throws Exception { - checkXssWithResourceName("\"); alert(123);//"); - } - - private void checkXssWithResourceName(String resourceName) throws Exception { - LockableResourcesManager.get().createResource(resourceName); - - j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); - j.jenkins.setAuthorizationStrategy(new FullControlOnceLoggedInAuthorizationStrategy()); - - JenkinsRule.WebClient wc = j.createWebClient(); - wc.login("user"); - - final AtomicReference lastAlertReceived = new AtomicReference<>(); - wc.setAlertHandler(new AlertHandler() { - @Override - public void handleAlert(Page page, String s) { - lastAlertReceived.set(s); - } + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Test + public void regularCase() throws Exception { + checkXssWithResourceName("resource1"); + } + + @Test + @Issue("SECURITY-1361") + public void noXssOnClick() throws Exception { + checkXssWithResourceName("\"); alert(123);//"); + } + + private void checkXssWithResourceName(String resourceName) throws Exception { + LockableResourcesManager.get().createResource(resourceName); + + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + j.jenkins.setAuthorizationStrategy(new FullControlOnceLoggedInAuthorizationStrategy()); + + JenkinsRule.WebClient wc = j.createWebClient(); + wc.login("user"); + + final AtomicReference lastAlertReceived = new AtomicReference<>(); + wc.setAlertHandler( + new AlertHandler() { + @Override + public void handleAlert(Page page, String s) { + lastAlertReceived.set(s); + } }); - - HtmlPage htmlPage = wc.goTo("lockable-resources"); - assertThat(lastAlertReceived.get(), nullValue()); - - // currently only one button but perhaps in future version of the core/plugin, - // other buttons will be added to the layout - List allButtons = htmlPage.getDocumentElement().getElementsByTagName("button"); - assertThat(allButtons.size(), greaterThanOrEqualTo(1)); - - HtmlElement reserveButton = null; - for (HtmlElement b : allButtons) { - String onClick = b.getAttribute("onClick"); - if (onClick != null && onClick.contains("reserve")) { - reserveButton = b; - } - } - assertThat(reserveButton, not(nullValue())); - - try { - HtmlElementUtil.click(reserveButton); - } catch (FailingHttpStatusCodeException e) { - // only happen if we have a XSS, but it's managed using the AlertHandler to ensure it's a XSS - // and not just an invalid page - } - assertThat(lastAlertReceived.get(), nullValue()); + + HtmlPage htmlPage = wc.goTo("lockable-resources"); + assertThat(lastAlertReceived.get(), nullValue()); + + // currently only one button but perhaps in future version of the core/plugin, + // other buttons will be added to the layout + List allButtons = htmlPage.getDocumentElement().getElementsByTagName("button"); + assertThat(allButtons.size(), greaterThanOrEqualTo(1)); + + HtmlElement reserveButton = null; + for (HtmlElement b : allButtons) { + String onClick = b.getAttribute("onClick"); + if (onClick != null && onClick.contains("reserve")) { + reserveButton = b; + } + } + assertThat(reserveButton, not(nullValue())); + + try { + HtmlElementUtil.click(reserveButton); + } catch (FailingHttpStatusCodeException e) { + // only happen if we have a XSS, but it's managed using the AlertHandler to ensure it's a XSS + // and not just an invalid page } + assertThat(lastAlertReceived.get(), nullValue()); + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java index 5f3cedee9..e2ff84e04 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java @@ -1,280 +1,64 @@ -/* - * The MIT License - * - * Copyright 2014 Aki Asikainen. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - package org.jenkins.plugins.lockableresources; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; -import hudson.model.AbstractBuild; -import hudson.model.Run; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; -/** - * - * @author aki - */ public class LockableResourceTest { - LockableResource instance; - - public LockableResourceTest() { - } - - @BeforeClass - public static void setUpClass() { - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - this.instance = new LockableResource("r1", "d1", "l1 l2", ""); - } - - @After - public void tearDown() { - } - - /** - * Test of getName method, of class LockableResource. - */ - @Test - public void testGetName() { - System.out.println("getName"); - String expResult = "r1"; - String result = instance.getName(); - assertEquals(expResult, result); - } - - /** - * Test of getDescription method, of class LockableResource. - */ - @Test - public void testGetDescription() { - System.out.println("getDescription"); - String expResult = "d1"; - String result = instance.getDescription(); - assertEquals(expResult, result); - } - - /** - * Test of getLabels method, of class LockableResource. - */ - @Test - public void testGetLabels() { - System.out.println("getLabels"); - String expResult = "l1 l2"; - String result = instance.getLabels(); - assertEquals(expResult, result); - } - - /** - * Test of getReservedBy method, of class LockableResource. - */ - @Test - public void testGetReservedBy() { - System.out.println("getReservedBy"); - String expResult = null; - String result = instance.getReservedBy(); - assertEquals(expResult, result); - } - - /** - * Test of isReserved method, of class LockableResource. - */ - @Test - public void testIsReserved() { - System.out.println("isReserved"); - boolean expResult = false; - boolean result = instance.isReserved(); - assertEquals(expResult, result); - } - - /** - * Test of isQueued method, of class LockableResource. - */ - @Test - public void testIsQueued_0args() { - System.out.println("isQueued"); - boolean expResult = false; - boolean result = instance.isQueued(); - assertEquals(expResult, result); - } - - /** - * Test of isQueued method, of class LockableResource. - */ - @Test - public void testIsQueued_int() { - System.out.println("isQueued"); - int taskId = 0; - boolean expResult = false; - boolean result = instance.isQueued(taskId); - assertEquals(expResult, result); - } - - /** - * Test of isQueuedByTask method, of class LockableResource. - */ - @Test - public void testIsQueuedByTask() { - System.out.println("isQueuedByTask"); - int taskId = 1; - boolean expResult = false; - boolean result = instance.isQueuedByTask(taskId); - assertEquals(expResult, result); - } - - /** - * Test of unqueue method, of class LockableResource. - */ - @Test - public void testUnqueue() { - System.out.println("unqueue"); - instance.unqueue(); - } - - /** - * Test of isLocked method, of class LockableResource. - */ - @Test - public void testIsLocked() { - System.out.println("isLocked"); - boolean expResult = false; - boolean result = instance.isLocked(); - assertEquals(expResult, result); - } - - /** - * Test of getBuild method, of class LockableResource. - */ - @Test - public void testGetBuild() { - System.out.println("getBuild"); - Run expResult = null; - Run result = instance.getBuild(); - assertEquals(expResult, result); - } - - /** - * Test of setBuild method, of class LockableResource. - */ - @Test - public void testSetBuild() { - System.out.println("setBuild"); - AbstractBuild lockedBy = null; - instance.setBuild(lockedBy) ; - } - - /** - * Test of getQueueItemId method, of class LockableResource. - */ - @Test - public void testGetQueueItemId() { - System.out.println("getQueueItemId"); - long expResult = 0; - long result = instance.getQueueItemId(); - assertEquals(expResult, result); - } - - /** - * Test of getQueueItemProject method, of class LockableResource. - */ - @Test - public void testGetQueueItemProject() { - System.out.println("getQueueItemProject"); - String expResult = null; - String result = instance.getQueueItemProject(); - assertEquals(expResult, result); - } - - /** - * Test of setReservedBy method, of class LockableResource. - */ - @Test - public void testSetReservedBy() { - System.out.println("setReservedBy"); - String userName = ""; - instance.setReservedBy(userName); - } - - /** - * Test of unReserve method, of class LockableResource. - */ - @Test - public void testUnReserve() { - System.out.println("unReserve"); - instance.unReserve(); - } - - /** - * Test of reset method, of class LockableResource. - */ - @Test - public void testReset() { - System.out.println("reset"); - instance.reset(); - } - - /** - * Test of toString method, of class LockableResource. - */ - @Test - public void testToString() { - System.out.println("toString"); - String expResult = "r1"; - String result = instance.toString(); - assertEquals(expResult, result); - } - - - /** - * Test of equals method, of class LockableResource. - */ - @Test - public void testEquals() { - System.out.println("equals"); - Object obj = null; - boolean expResult = false; - boolean result = instance.equals(obj); - assertEquals(expResult, result); - } - - /** - * Test of hashCode method, of class LockableResource. - */ - @Test - public void testHashCode() { - System.out.println("hashCode"); - int expResult = 0; - int result = instance.hashCode(); - } + LockableResource instance = new LockableResource("r1"); + + // Not sure how useful this is... + @Test + public void testGetters() { + assertEquals("r1", instance.getName()); + assertEquals("", instance.getDescription()); + assertEquals("", instance.getLabels()); + assertNull(instance.getReservedBy()); + assertFalse(instance.isReserved()); + assertFalse(instance.isQueued()); + assertFalse(instance.isQueued(0)); + assertFalse(instance.isQueuedByTask(1)); + assertFalse(instance.isLocked()); + assertNull(instance.getBuild()); + assertEquals(0, instance.getQueueItemId()); + assertNull(instance.getQueueItemProject()); + } + + @Test + public void testUnqueue() { + instance.unqueue(); + } + + @Test + public void testSetBuild() { + instance.setBuild(null); + } + + @Test + public void testSetReservedBy() { + instance.setReservedBy(""); + } + + @Test + public void testUnReserve() { + instance.unReserve(); + } + + @Test + public void testReset() { + instance.reset(); + } + + @Test + public void testToString() { + assertEquals("r1", instance.toString()); + } + + @Test + public void testEquals() { + assertFalse(instance.equals(null)); + } } From ea89c91a3ffe144776d7cadfaac0a5a48bf58661 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 12 Oct 2019 10:17:53 +0200 Subject: [PATCH 0045/1078] [maven-release-plugin] prepare release lockable-resources-2.6 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9f0588c07..b6c6395e9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,12 +6,12 @@ org.jenkins-ci.plugins plugin 3.47 - + org.6wind.jenkins lockable-resources - ${revision}${changelist} + 2.6 hpi Lockable Resources plugin @@ -46,7 +46,7 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - ${scmTag} + lockable-resources-2.6 From 292d3c55a7928efe2d39bcc656fc278e316e5680 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 12 Oct 2019 10:18:12 +0200 Subject: [PATCH 0046/1078] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b6c6395e9..d339ece1f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - 2.6 + ${revision}${changelist} hpi Lockable Resources plugin @@ -46,11 +46,11 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - lockable-resources-2.6 + ${scmTag} - 2.6 + 2.7 -SNAPSHOT 8 2.12 From c8eed5d3f169b429e68739433bde69eaf0edabcd Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 15 Oct 2019 23:55:32 +0200 Subject: [PATCH 0047/1078] Add tests demonstrating JENKINS-50176 & JENKINS-54541 Since the outcome is the same, it doesn't hurt to demonstrate the different ways in which this bug occurs. --- .../lockableresources/LockStepTest.java | 109 +++++++++++++++++- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 19b3e0b20..02127a83c 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -10,6 +10,7 @@ import hudson.model.*; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.Semaphore; @@ -840,15 +841,113 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { } @Test - public void lockWithInvalidLabel() throws Exception { + @Issue("JENKINS-50176") + public void lockWithLabelFillsVariable() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock(label: 'invalidLabel', variable: 'var', quantity: 1) {\n" - + " echo \"Resource locked: ${env.var}\"\n" - + "}\n" - + "echo 'Finish'")); + "lock(label: 'label1', variable: 'someVar') {\n" + + " semaphore 'wait-inside'\n" + + " echo \"VAR IS $env.someVar\"\n" + + "}")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-inside/1", b1); + + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); + p2.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', variable: 'someVar2') {\n" + + " echo \"VAR2 IS $env.someVar2\"\n" + + "}")); + WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + j.waitForMessage("is locked, waiting...", b2); + isPaused(b2, 1, 1); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource", b1); + isPaused(b1, 1, 0); + + // Now job 2 should get and release the lock... + j.waitForCompletion(b1); + j.waitForCompletion(b2); + isPaused(b2, 1, 0); + + // Variable should have been filled in both cases + j.assertLogContains("VAR IS resource1", b1); + j.assertLogContains("VAR2 IS resource1", b2); + } + + @Test + @Issue("JENKINS-50176") + public void paralleLockWithLabelFillsVariable() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "parallel p1: {\n" + + " lock(label: 'label1', variable: 'someVar') {\n" + + " semaphore 'wait-inside'\n" + + " echo \"VAR IS $env.someVar\"\n" + + " }\n" + + "},\n" + + "p2: {\n" + + " semaphore 'wait-outside'\n" + + " lock(label: 'label1', variable: 'someVar2') {\n" + + " echo \"VAR2 IS $env.someVar2\"\n" + + " }\n" + + "}")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait-outside/1", b1); + SemaphoreStep.waitForStart("wait-inside/1", b1); + SemaphoreStep.success("wait-outside/1", null); + + j.waitForMessage("is locked, waiting...", b1); + isPaused(b1, 2, 1); + + // Unlock resources + SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("Lock released on resource", b1); + isPaused(b1, 2, 0); + + // Now the second parallel branch should get and release the lock... + j.waitForCompletion(b1); + isPaused(b1, 2, 0); + + // Variable should have been filled in both cases + j.assertLogContains("VAR IS resource1", b1); + j.assertLogContains("VAR2 IS resource1", b1); + } + + @Test + @Issue("JENKINS-54541") + public void unreserveSetsVariable() throws Exception { + LockableResourcesManager lm = LockableResourcesManager.get(); + lm.createResourceWithLabel("resource1", "label1"); + lm.reserve(Arrays.asList(lm.fromName("resource1")), "test"); + + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label1', variable: 'someVar') {\n" + + " echo \"VAR IS $env.someVar\"\n" + + "}")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + + j.waitForMessage("is locked, waiting...", b1); + lm.unreserve(Arrays.asList(lm.fromName("resource1"))); + j.assertBuildStatusSuccess(j.waitForCompletion(b1)); + + // Variable should have been filled + j.assertLogContains("VAR IS resource1", b1); + } + + @Test + public void lockWithInvalidLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition("lock(label: 'invalidLabel') {\n" + "}\n")); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.FAILURE, b1); From 4bcac9476d39a899eb72c869aeaf3cc627422a3d Mon Sep 17 00:00:00 2001 From: Stefan Rystedt Date: Tue, 4 Dec 2018 09:32:01 +0100 Subject: [PATCH 0048/1078] Changed the handling of variabel names for locks The previous version was broken for pipeline steps. Now we save the name in the QueuedContextStruct so we can retrieve it when we can get the lock --- .../BackwardCompatibility.java | 2 +- .../lockableresources/LockStepExecution.java | 9 +++------ .../LockableResourcesManager.java | 17 ++++++++--------- .../queue/QueuedContextStruct.java | 15 ++++++++++++++- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java index 6f3f20e3e..d990db53b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java @@ -36,7 +36,7 @@ public static void compatibilityMigration() { List resourcesNames = new ArrayList<>(); resourcesNames.add(resource.getName()); LockableResourcesStruct resourceHolder = new LockableResourcesStruct(resourcesNames, "", 0); - LockableResourcesManager.get().queueContext(queuedContext, Arrays.asList(resourceHolder), resource.getName()); + LockableResourcesManager.get().queueContext(queuedContext, Arrays.asList(resourceHolder), resource.getName(), null); } queuedContexts.clear(); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index e136ecee5..46184222d 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -81,7 +81,7 @@ public boolean start() throws Exception { listener.getLogger().println("[" + step + "] is locked, waiting..."); } LockableResourcesManager.get() - .queueContext(getContext(), resourceHolderList, step.toString()); + .queueContext(getContext(), resourceHolderList, step.toString(), step.variable); } // proceed is called inside lock if execution is possible return false; } @@ -113,7 +113,7 @@ public static void proceed( context .newBodyInvoker() .withCallback( - new Callback(resourcenames, resourceDescription, variable, inversePrecedence)); + new Callback(resourcenames, resourceDescription, inversePrecedence)); if (variable != null && variable.length() > 0) // set the variable for the duration of the block bodyInvoker.withContext( @@ -143,24 +143,21 @@ private static final class Callback extends BodyExecutionCallback.TailCall { private final List resourceNames; private final String resourceDescription; - private final String variable; private final boolean inversePrecedence; Callback( List resourceNames, String resourceDescription, - String variable, boolean inversePrecedence) { this.resourceNames = resourceNames; this.resourceDescription = resourceDescription; - this.variable = variable; this.inversePrecedence = inversePrecedence; } protected void finished(StepContext context) throws Exception { LockableResourcesManager.get() .unlockNames( - this.resourceNames, context.get(Run.class), this.variable, this.inversePrecedence); + this.resourceNames, context.get(Run.class), this.inversePrecedence); context .get(TaskListener.class) .getLogger() diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 57b0c41f2..0dce26179 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -397,13 +397,12 @@ private synchronized void freeResources( public synchronized void unlock( List resourcesToUnLock, @Nullable Run build) { - unlock(resourcesToUnLock, build, null, false); + unlock(resourcesToUnLock, build, false); } public synchronized void unlock( @Nullable List resourcesToUnLock, @Nullable Run build, - String requiredVar, boolean inversePrecedence) { List resourceNamesToUnLock = new ArrayList<>(); if (resourcesToUnLock != null) { @@ -412,13 +411,12 @@ public synchronized void unlock( } } - this.unlockNames(resourceNamesToUnLock, build, requiredVar, inversePrecedence); + this.unlockNames(resourceNamesToUnLock, build, inversePrecedence); } public synchronized void unlockNames( @Nullable List resourceNamesToUnLock, @Nullable Run build, - String requiredVar, boolean inversePrecedence) { // make sure there is a list of resource names to unlock if (resourceNamesToUnLock == null || (resourceNamesToUnLock.isEmpty())) { @@ -482,7 +480,7 @@ public synchronized void unlockNames( + " hard killed. More information at Level.FINE if debug is needed."); LOGGER.log( Level.FINE, "Can not get the Run object from the context to proceed with lock", e); - unlockNames(remainingResourceNamesToUnLock, build, requiredVar, inversePrecedence); + unlockNames(remainingResourceNamesToUnLock, build, inversePrecedence); return; } } @@ -512,7 +510,7 @@ public synchronized void unlockNames( resourceNamesToLock, nextContext.getContext(), nextContext.getResourceDescription(), - requiredVar, + nextContext.getVariableName(), inversePrecedence); } } @@ -701,7 +699,7 @@ public synchronized void unreserve(List resources) { resourceNamesToLock, nextContext.getContext(), nextContext.getResourceDescription(), - null, + nextContext.getVariableName(), false); } save(); @@ -856,7 +854,8 @@ public synchronized Set checkResourcesAvailability( public synchronized void queueContext( StepContext context, List requiredResources, - String resourceDescription) { + String resourceDescription, + String variableName) { for (QueuedContextStruct entry : this.queuedContexts) { if (entry.getContext() == context) { return; @@ -864,7 +863,7 @@ public synchronized void queueContext( } this.queuedContexts.add( - new QueuedContextStruct(context, requiredResources, resourceDescription)); + new QueuedContextStruct(context, requiredResources, resourceDescription, variableName)); save(); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java index aa5560230..ed25a7d2e 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/QueuedContextStruct.java @@ -35,13 +35,19 @@ public class QueuedContextStruct implements Serializable { */ private String resourceDescription; + /* + * Name of the variable to save the locks taken. + */ + private String variableName; + /* * Constructor for the QueuedContextStruct class. */ - public QueuedContextStruct(StepContext context, List lockableResourcesStruct, String resourceDescription) { + public QueuedContextStruct(StepContext context, List lockableResourcesStruct, String resourceDescription, String variableName) { this.context = context; this.lockableResourcesStruct = lockableResourcesStruct; this.resourceDescription = resourceDescription; + this.variableName = variableName; } /* @@ -65,5 +71,12 @@ public String getResourceDescription() { return this.resourceDescription; } + /* + * Gets the variable name to save the locks taken. + */ + public String getVariableName() { + return this.variableName; + } + private static final long serialVersionUID = 1L; } From 521667b31f0f329671d5c7e8fa1660f78749766c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 1 Nov 2019 23:43:10 +0100 Subject: [PATCH 0049/1078] LockableResourcesQueueTaskDispatcher.java : avoid "Waiting for resources []" when a script is used (#147) --- .../LockableResourcesQueueTaskDispatcher.java | 25 ++++++++++++++++--- .../queue/LockableResourcesStruct.java | 3 +++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java index b651d7b8f..ec8b25002 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java @@ -32,6 +32,7 @@ import org.jenkins.plugins.lockableresources.LockableResource; import org.jenkins.plugins.lockableresources.LockableResourcesManager; +import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -159,10 +160,28 @@ public BecauseResourcesLocked(LockableResourcesStruct r) { @Override public String getShortDescription() { - if (this.rscStruct.label.isEmpty()) - return "Waiting for resources " + rscStruct.required.toString(); - else + if (this.rscStruct.label.isEmpty()) { + if (this.rscStruct.required.size() > 0) { + return "Waiting for resource instances " + rscStruct.required.toString(); + } else { + final SecureGroovyScript systemGroovyScript = this.rscStruct.getResourceMatchScript(); + if (systemGroovyScript != null) { + // Empty or not... just keep the logic in sync + // with tryQueue() in LockableResourcesManager + if (systemGroovyScript.getScript().isEmpty()) { + return "Waiting for resources identified by custom script (which is empty)"; + } else { + return "Waiting for resources identified by custom script"; + } + } + // TODO: Developers should extend here if LockableResourcesStruct is extended + LOGGER.log(Level.WARNING, "Failed to classify reason of waiting for resource: " + + this.rscStruct.toString()); + return "Waiting for lockable resources"; + } + } else { return "Waiting for resources with label " + rscStruct.label; + } } } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index 05baa3940..fef1bbcea 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -22,6 +22,9 @@ public class LockableResourcesStruct implements Serializable { + // Note to developers: if the set of selection criteria variables evolves, + // do not forget to update LockableResourcesQueueTaskDispatcher.java with + // class BecauseResourcesLocked method getShortDescription() for user info. public List required; public String label; public String requiredVar; From b82480afe23fab4ce83d03611f1163c54de388c4 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 2 Nov 2019 00:12:08 +0100 Subject: [PATCH 0050/1078] [maven-release-plugin] prepare release lockable-resources-2.7 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d339ece1f..52f951f29 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - ${revision}${changelist} + 2.7 hpi Lockable Resources plugin @@ -46,7 +46,7 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - ${scmTag} + lockable-resources-2.7 From e34a13ebd58b61051dc706bb9118142688b29db3 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sat, 2 Nov 2019 00:12:25 +0100 Subject: [PATCH 0051/1078] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 52f951f29..2cad3b37d 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - 2.7 + ${revision}${changelist} hpi Lockable Resources plugin @@ -46,11 +46,11 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - lockable-resources-2.7 + ${scmTag} - 2.7 + 2.8 -SNAPSHOT 8 2.12 From e41a02fff639b7b6fdf33e960d93e1ed653fd8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scheibe?= Date: Thu, 14 Nov 2019 01:17:33 +0100 Subject: [PATCH 0052/1078] Fix typos & Javadoc (#163) --- README.md | 6 +++--- .../plugins/lockableresources/LockStepExecution.java | 2 +- .../plugins/lockableresources/LockableResource.java | 2 +- .../lockableresources/LockableResourcesManager.java | 2 +- .../queue/LockableResourcesStruct.java | 4 +--- .../lockableresources/ConfigurationAsCodeTest.java | 10 +++++----- .../plugins/lockableresources/LockStepTest.java | 2 +- 7 files changed, 13 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d2be67c88..08c5b5990 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Please see the help item for each field for details. ### Using a resource in a pipeline job When the `lock` step is used in a Pipeline, if the resource to be locked isn't -already defined in the Jenkins global configuration, an ephermal resource is +already defined in the Jenkins global configuration, an ephemeral resource is used: These resources only exist as long as any running build is referencing them. @@ -95,7 +95,7 @@ unclassified: ## Contributing -If you want to contribute to this plugin, you probably will need a Jenkins plugin developement +If you want to contribute to this plugin, you probably will need a Jenkins plugin development environment. This basically means a current version of Java (Java 8 should probably be okay for now) and [Apache Maven]. See the [Jenkins Plugin Tutorial] for details. @@ -108,7 +108,7 @@ should create a plugin as `target/*.hpi`, which you can install in your Jenkins $ mvn hpi:run -Djenkins.version=2.164.1 allows you to spin up a test Jenkins instance on [localhost] to test your -local changes before commiting. +local changes before committing. [Apache Maven]: https://maven.apache.org/ [Jenkins Plugin Tutorial]: https://jenkins.io/doc/developer/tutorial/prepare/ diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 46184222d..9a21a39ad 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -174,7 +174,7 @@ public void stop(Throwable cause) throws Exception { if (!cleaned) { LOGGER.log( Level.WARNING, - "Cannot remove context from lockable resource witing list. The context is not in the waiting list."); + "Cannot remove context from lockable resource waiting list. The context is not in the waiting list."); } getContext().onFailure(cause); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 83a319324..ae7fb96e5 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -252,7 +252,7 @@ public String getLockCause() { return build; } - /** @see {@link WithBridgeMethods} */ + /** @see WithBridgeMethods */ @Deprecated private Object getAbstractBuild(final Run owner, final Class targetClass) { return owner instanceof AbstractBuild ? (AbstractBuild) owner : null; diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 0dce26179..f1ef9f6cf 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -276,7 +276,7 @@ public synchronized List tryQueue( // if did not get wanted amount or did not get all final int required_amount; if (candidatesByScript && candidates.isEmpty()) { - /** + /* * If the groovy script does not return any candidates, it means nothing is needed, even if a * higher amount is specified. A valid use case is a Matrix job, when not all configurations * need resources. diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index fef1bbcea..269fa9103 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -107,9 +107,7 @@ public LockableResourcesStruct( * LockableResource} matches the condition. * * @return System Groovy Script if defined - * @see - * LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, - * java.util.Map) + * @see LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, java.util.Map) * @since TODO */ @CheckForNull diff --git a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java index 9f1c10e94..d828e117b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java @@ -29,11 +29,11 @@ public void should_support_configuration_as_code() throws Exception { 1, declaredResources.size()); - LockableResource declaredResouce = declaredResources.get(0); - assertEquals("Resource_A", declaredResouce.getName()); - assertEquals("Description_A", declaredResouce.getDescription()); - assertEquals("Label_A", declaredResouce.getLabels()); - assertEquals("Reserved_A", declaredResouce.getReservedBy()); + LockableResource declaredResource = declaredResources.get(0); + assertEquals("Resource_A", declaredResource.getName()); + assertEquals("Description_A", declaredResource.getDescription()); + assertEquals("Label_A", declaredResource.getLabels()); + assertEquals("Reserved_A", declaredResource.getReservedBy()); List resources = LockableResourcesManager.get().getResources(); assertEquals( diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 02127a83c..c00cda224 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -881,7 +881,7 @@ public void lockWithLabelFillsVariable() throws Exception { @Test @Issue("JENKINS-50176") - public void paralleLockWithLabelFillsVariable() throws Exception { + public void parallelLockWithLabelFillsVariable() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( From c04b19e934cc7248092e0b59cebbd1ea503a51cf Mon Sep 17 00:00:00 2001 From: Bryan Date: Tue, 26 Nov 2019 07:33:44 +0100 Subject: [PATCH 0053/1078] Reset resources on configuration update (#167) Fixes #166. --- .../plugins/lockableresources/LockableResourcesManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index f1ef9f6cf..e02aba22a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -721,6 +721,8 @@ public synchronized void reset(List resources) { public boolean configure(StaplerRequest req, JSONObject json) throws FormException { BulkChange bc = new BulkChange(this); try { + // reset resources to default before data-binding + this.resources = new ArrayList<>(); req.bindJSON(this, json); bc.commit(); } catch (IOException exception) { From eb9395d796c0db25e5c0257531247bcbad7a49e0 Mon Sep 17 00:00:00 2001 From: Eisenmann Markus Date: Wed, 18 Dec 2019 10:23:45 +0100 Subject: [PATCH 0054/1078] Implement candidate-cache for resource-selection by label(s) or script to prevent performance-regression --- .../LockableResourcesManager.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index e02aba22a..ed8648bfa 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -8,6 +8,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package org.jenkins.plugins.lockableresources; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.Nullable; import hudson.BulkChange; @@ -18,6 +20,7 @@ import java.io.PrintStream; import java.util.*; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; @@ -39,6 +42,7 @@ public class LockableResourcesManager extends GlobalConfiguration { @Deprecated private transient int defaultPriority; @Deprecated private transient String priorityParameterName; private List resources; + private transient Cache> cachedCandidates = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(); /** * Only used when this lockable resource is tried to be locked by {@link LockStep}, otherwise @@ -254,18 +258,21 @@ public synchronized List tryQueue( return null; } - boolean candidatesByScript = false; - List candidates = new ArrayList<>(); final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); - if (requiredResources.label != null - && requiredResources.label.isEmpty() - && systemGroovyScript == null) { - candidates = requiredResources.required; - } else if (systemGroovyScript == null) { - candidates = getResourcesWithLabel(requiredResources.label, params); - } else { - candidates = getResourcesMatchingScript(systemGroovyScript, params); - candidatesByScript = true; + boolean candidatesByScript = (systemGroovyScript != null); + List candidates = requiredResources.required; // default canditates + + if (candidatesByScript || + (requiredResources.label != null && !requiredResources.label.isEmpty())) { + candidates = cachedCandidates.getIfPresent(queueItemId); + if (candidates != null) { + candidates.retainAll(resources); + } else { + candidates = (systemGroovyScript == null) + ? getResourcesWithLabel(requiredResources.label, params) + : getResourcesMatchingScript(systemGroovyScript, params); + cachedCandidates.put(queueItemId, candidates); + } } for (LockableResource rs : candidates) { From 58c909bc91719bb9c100d4b570c6f05e207b7e6f Mon Sep 17 00:00:00 2001 From: Johnny Willemsen Date: Tue, 4 Feb 2020 11:37:05 +0100 Subject: [PATCH 0055/1078] Updated Maintenance in README.md (#175) Updated shield link to 2020 and added an explicit link, the default link returns a 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08c5b5990..68154173d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/lockable-resources.svg?color=blue)](https://plugins.jenkins.io/lockable-resources) [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) [![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) -[![Maintenance](https://img.shields.io/maintenance/yes/2019.svg)]() +[![Maintenance](https://img.shields.io/maintenance/yes/2020.svg)](https://github.com/jenkinsci/lockable-resources-plugin) This plugin allows defining lockable resources (such as printers, phones, computers, etc.) that can be used by builds. If a build requires a resource From 2efd8534b9b82297bea23ed291d19bffd11949f3 Mon Sep 17 00:00:00 2001 From: Johnny Willemsen Date: Tue, 4 Feb 2020 17:15:46 +0100 Subject: [PATCH 0056/1078] Updated README.md to add a link to the pipeline steps documentaiton (#177) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 68154173d..5229644b7 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,10 @@ lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { } ``` +Detailed documentation can be found as part of the +[Pipeline Steps](https://jenkins.io/doc/pipeline/steps/lockable-resources/) +documentation. + ## Configuration as Code This plugin can be configured via From cf94d6a850bf0da1f0a6a2212763070ced386038 Mon Sep 17 00:00:00 2001 From: Bryan Date: Sun, 23 Feb 2020 16:40:34 +0100 Subject: [PATCH 0057/1078] Only reset resources which are not currently locked (#174) Fixes #172 --- .../plugins/lockableresources/LockableResourcesManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index e02aba22a..b44d8a0f0 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -721,8 +721,8 @@ public synchronized void reset(List resources) { public boolean configure(StaplerRequest req, JSONObject json) throws FormException { BulkChange bc = new BulkChange(this); try { - // reset resources to default before data-binding - this.resources = new ArrayList<>(); + // reset resources to default which are not currently locked + this.resources.removeIf(resource -> !resource.isLocked()); req.bindJSON(this, json); bc.commit(); } catch (IOException exception) { From f78879fa335f7edf8d8455d3af167bbad5b56cd9 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Wed, 26 Feb 2020 21:39:08 +0100 Subject: [PATCH 0058/1078] Updating dependencies in pom.xml (#182) (Jenkins 2.138.4 baseline) --- pom.xml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 2cad3b37d..15a29644f 100644 --- a/pom.xml +++ b/pom.xml @@ -53,12 +53,17 @@ 2.8 -SNAPSHOT 8 - 2.12 - 2.60.3 + 3.4 + 2.138.4 1.25 + + org.jenkins-ci.plugins + structs + 1.18 + org.jenkins-ci.plugins mailer @@ -77,7 +82,7 @@ org.jenkins-ci.plugins script-security - 1.33 + 1.39 com.infradna.tool @@ -109,7 +114,7 @@ org.jenkins-ci.plugins.workflow workflow-cps - 2.10 + 2.14 test From 827dc61ddbc78a4f670335e9b25e32ce415b4029 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Wed, 26 Feb 2020 23:55:11 +0100 Subject: [PATCH 0059/1078] Import old changelog from wiki (#188) --- CHANGELOG.old.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 +++-- 2 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 CHANGELOG.old.md diff --git a/CHANGELOG.old.md b/CHANGELOG.old.md new file mode 100644 index 000000000..946e52daf --- /dev/null +++ b/CHANGELOG.old.md @@ -0,0 +1,88 @@ +# Old Changelog + +This is the old changelog, see +[GitHub Releases](https://github.com/jenkinsci/lockable-resources-plugin/releases) +for recent versions. + +## Release 2.5 (2019-03-25) + +- [Fix security issue](https://jenkins.io/security/advisory/2019-03-25/) + +## Release 2.4 (2019-01-18) + +- [JENKINS-46555](https://issues.jenkins-ci.org/browse/JENKINS-46555) - Fix NPE + on invalid entries. + +## Release 2.3 (2018-06-26) + +- [JENKINS-34433](https://issues.jenkins-ci.org/browse/JENKINS-34433) - Signal + queued Pipeline tasks on unreserve + +- Allow locking multiple resources in Pipeline + +## Release 2.2 (2018-03-06) + +- [JENKINS-40997](https://issues.jenkins-ci.org/browse/JENKINS-40997) - New + configuration option to get the name of the locked resource inside the lock + block (Pipeline). + +- [JENKINS-49734](https://issues.jenkins-ci.org/browse/JENKINS-49734) - + Add a PauseAction to the build when waiting for locking, so Pipeline + representations in the UI are correctly shown. +- [JENKINS-43574](https://issues.jenkins-ci.org/browse/JENKINS-43574) - Fixed + the "empty" resources lock (message: "acquired lock on \[\]") + +## Release 2.1 (2017-11-13) + +- [JENKINS-47235](https://issues.jenkins-ci.org/browse/JENKINS-47235) - + Trim whitespace from resource names. +- [JENKINS-47754](https://issues.jenkins-ci.org/browse/JENKINS-47754) - + Fix broken Freestyle behavior. + +## Release 1.11.2 (2017-03-15) + +- [JENKINS-40368](https://issues.jenkins-ci.org/browse/JENKINS-40368) - Locked + resources are not always freed up on Pipeline hard kill when there + are other pipelines waiting on the Resource + +## Release 1.11.1 (2017-02-20) + +- [JENKINS-40879](https://issues.jenkins-ci.org/browse/JENKINS-40879) - Locked + areas are executed multiple times in parallel + +## Release 1.11 (2016-12-19) + +- [JENKINS-34268](https://issues.jenkins-ci.org/browse/JENKINS-34268) - + lock multiple resources concurrently +- [JENKINS-34273](https://issues.jenkins-ci.org/browse/JENKINS-34273) - + add the number of resources to lock from a given label + +## Release 1.10 (2016-07-12) + +- [JENKINS-36479](https://issues.jenkins-ci.org/browse/JENKINS-36479) - + properly clean up resources locked by hard-killed or deleted while + in progress Pipeline builds. + +## Release 1.9 (2016-06-01) + +- Reserved resources parameter visibility in environment (related to + SECURITY-170) + +## Release 1.8 (2016-04-14) + +- Pipeline compatibility: lock step + +## Release 1.2 (2014-02-05) + +- Manual reservation/un-reservation of resources now require specific + permissions + +## Release 1.1 (2014-02-03) + +- Allow jobs to require a subset of specified resources (the number of required + resources is configurable) +- Allow manual reservation/un-reservation of resources + +## Release 1.0 (2013-12-12) + +- Initial release diff --git a/README.md b/README.md index 5229644b7..796c47976 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,8 @@ lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { } ``` -Detailed documentation can be found as part of the -[Pipeline Steps](https://jenkins.io/doc/pipeline/steps/lockable-resources/) +Detailed documentation can be found as part of the +[Pipeline Steps](https://jenkins.io/doc/pipeline/steps/lockable-resources/) documentation. ## Configuration as Code @@ -93,9 +93,8 @@ unclassified: ## Changelog * See [GitHub Releases](https://github.com/jenkinsci/lockable-resources-plugin/releases) - for recent versions -* See the [plugin's Wiki page](https://wiki.jenkins.io/display/JENKINS/Lockable+Resources+Plugin#LockableResourcesPlugin-Changelog) - for versions 2.5 and older + for recent versions. +* See the [old changelog](CHANGELOG.old.md) for versions 2.5 and older. ## Contributing From 23eaf37cf72bbdc2b30dee65d51389ac3e3a1a22 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Thu, 27 Feb 2020 00:22:30 +0100 Subject: [PATCH 0060/1078] Removing usage of deprecated APIs in LockStep(Execution) (#183) --- .../plugins/lockableresources/LockStep.java | 30 ++++++--- .../lockableresources/LockStepExecution.java | 61 +++++++++---------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index bedff670a..2a8755100 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -3,20 +3,25 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.Extension; import hudson.model.AutoCompletionCandidates; +import hudson.model.TaskListener; import hudson.util.FormValidation; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; -import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; +import org.jenkinsci.plugins.workflow.steps.Step; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; -public class LockStep extends AbstractStepImpl implements Serializable { +public class LockStep extends Step implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -953609907239674360L; @CheckForNull public String resource = null; @@ -71,11 +76,7 @@ public void setExtra(List extra) { } @Extension - public static final class DescriptorImpl extends AbstractStepDescriptorImpl { - - public DescriptorImpl() { - super(LockStepExecution.class); - } + public static final class DescriptorImpl extends StepDescriptor { @Override public String getFunctionName() { @@ -105,8 +106,14 @@ public static FormValidation doCheckResource( @QueryParameter String value, @QueryParameter String label) { return LockStepResource.DescriptorImpl.doCheckLabel(label, value); } + + @Override + public Set> getRequiredContext() { + return Collections.singleton(TaskListener.class); + } } + @Override public String toString() { if (extra != null && !extra.isEmpty()) { return getResources().stream() @@ -135,4 +142,9 @@ public List getResources() { } return resources; } + + @Override + public StepExecution start(StepContext context) throws Exception { + return new LockStepExecution(this, context); + } } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 9a21a39ad..1a3dc1945 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -1,11 +1,12 @@ package org.jenkins.plugins.lockableresources; import com.google.common.base.Joiner; -import com.google.inject.Inject; import hudson.EnvVars; import hudson.model.Run; import hudson.model.TaskListener; import java.io.IOException; +import java.io.PrintStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -18,30 +19,30 @@ import org.jenkinsci.plugins.workflow.steps.BodyInvoker; import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander; import org.jenkinsci.plugins.workflow.steps.StepContext; -import org.jenkinsci.plugins.workflow.steps.StepContextParameter; import org.jenkinsci.plugins.workflow.support.actions.PauseAction; -public class LockStepExecution extends AbstractStepExecutionImpl { +public class LockStepExecution extends AbstractStepExecutionImpl implements Serializable { - private static final Joiner COMMA_JOINER = Joiner.on(','); + private static final long serialVersionUID = 1391734561272059623L; - @Inject(optional = true) - private LockStep step; + private static Joiner COMMA_JOINER = Joiner.on(','); - @StepContextParameter private transient Run run; + private static Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); - @StepContextParameter private transient TaskListener listener; + private final LockStep step; - @StepContextParameter private transient FlowNode node; - - private static final Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); + public LockStepExecution(LockStep step, StepContext context) { + super(context); + this.step = step; + } @Override public boolean start() throws Exception { step.validate(); - node.addAction(new PauseAction("Lock")); - listener.getLogger().println("Trying to acquire lock on [" + step + "]"); + getContext().get(FlowNode.class).addAction(new PauseAction("Lock")); + PrintStream logger = getContext().get(TaskListener.class).getLogger(); + logger.println("Trying to acquire lock on [" + step + "]"); List resourceHolderList = new ArrayList<>(); @@ -49,7 +50,7 @@ public boolean start() throws Exception { List resources = new ArrayList<>(); if (resource.resource != null) { if (LockableResourcesManager.get().createResource(resource.resource)) { - listener.getLogger().println("Resource [" + resource + "] did not exist. Created."); + logger.println("Resource [" + resource + "] did not exist. Created."); } resources.add(resource.resource); } @@ -59,8 +60,8 @@ public boolean start() throws Exception { // determine if there are enough resources available to proceed Set available = - LockableResourcesManager.get() - .checkResourcesAvailability(resourceHolderList, listener.getLogger(), null); + LockableResourcesManager.get().checkResourcesAvailability(resourceHolderList, logger, null); + Run run = getContext().get(Run.class); if (available == null || !LockableResourcesManager.get() .lock( @@ -73,12 +74,10 @@ public boolean start() throws Exception { // if the resource is known, we could output the active/blocking job/build LockableResource resource = LockableResourcesManager.get().fromName(step.resource); if (resource != null && resource.getBuildName() != null) { - listener - .getLogger() - .println("[" + step + "] is locked by " + resource.getBuildName() + ", waiting..."); + logger.println("[" + step + "] is locked by " + resource.getBuildName() + ", waiting..."); } else { - listener.getLogger().println("[" + step + "] is locked, waiting..."); + logger.println("[" + step + "] is locked, waiting..."); } LockableResourcesManager.get() .queueContext(getContext(), resourceHolderList, step.toString(), step.variable); @@ -112,14 +111,15 @@ public static void proceed( BodyInvoker bodyInvoker = context .newBodyInvoker() - .withCallback( - new Callback(resourcenames, resourceDescription, inversePrecedence)); - if (variable != null && variable.length() > 0) + .withCallback(new Callback(resourcenames, resourceDescription, inversePrecedence)); + if (variable != null && variable.length() > 0) { // set the variable for the duration of the block bodyInvoker.withContext( EnvironmentExpander.merge( context.get(EnvironmentExpander.class), new EnvironmentExpander() { + private static final long serialVersionUID = -3431466225193397896L; + @Override public void expand(EnvVars env) throws IOException, InterruptedException { final String resources = COMMA_JOINER.join(resourcenames); @@ -133,6 +133,7 @@ public void expand(EnvVars env) throws IOException, InterruptedException { env.override(variable, resources); } })); + } bodyInvoker.start(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); @@ -141,31 +142,27 @@ public void expand(EnvVars env) throws IOException, InterruptedException { private static final class Callback extends BodyExecutionCallback.TailCall { + private static final long serialVersionUID = -2024890670461847666L; private final List resourceNames; private final String resourceDescription; private final boolean inversePrecedence; - Callback( - List resourceNames, - String resourceDescription, - boolean inversePrecedence) { + Callback(List resourceNames, String resourceDescription, boolean inversePrecedence) { this.resourceNames = resourceNames; this.resourceDescription = resourceDescription; this.inversePrecedence = inversePrecedence; } + @Override protected void finished(StepContext context) throws Exception { LockableResourcesManager.get() - .unlockNames( - this.resourceNames, context.get(Run.class), this.inversePrecedence); + .unlockNames(this.resourceNames, context.get(Run.class), this.inversePrecedence); context .get(TaskListener.class) .getLogger() .println("Lock released on resource [" + resourceDescription + "]"); LOGGER.finest("Lock released on [" + resourceDescription + "]"); } - - private static final long serialVersionUID = 1L; } @Override @@ -178,6 +175,4 @@ public void stop(Throwable cause) throws Exception { } getContext().onFailure(cause); } - - private static final long serialVersionUID = 1L; } From 413355d64995f7863277f78a5d626de1560cf324 Mon Sep 17 00:00:00 2001 From: William Brode Date: Wed, 11 Mar 2020 16:18:55 -0700 Subject: [PATCH 0061/1078] JENKINS-57727: Make fromName() synchronized (#191) --- .../plugins/lockableresources/LockableResourcesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index b44d8a0f0..f5bf2645a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -177,7 +177,7 @@ public List getResourcesMatchingScript( return found; } - public LockableResource fromName(String resourceName) { + public synchronized LockableResource fromName(String resourceName) { if (resourceName != null) { for (LockableResource r : resources) { if (resourceName.equals(r.getName())) return r; From 987d06da8a978132d6c4435b84e6cba76c987a2d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Le Duigou Date: Tue, 17 Mar 2020 10:42:39 +0100 Subject: [PATCH 0062/1078] Adding french locale (#192) Signed-off-by: Jean-Baptiste Le Duigou --- .../actions/LockableResourcesRootAction.java | 4 ++-- .../lockableresources/Messages_fr.properties | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index f7f460d76..6f121181c 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -49,7 +49,7 @@ public class LockableResourcesRootAction implements RootAction { Messages.LockableResourcesRootAction_ViewPermission(), Messages._LockableResourcesRootAction_ViewPermission_Description(), Jenkins.ADMINISTER, PermissionScope.JENKINS); - + public static final String ICON = "/plugin/lockable-resources/img/device-24x24.png"; public String getIconFileName() { @@ -65,7 +65,7 @@ public String getUserName() { } public String getDisplayName() { - return "Lockable Resources"; + return Messages.LockableResourcesRootAction_PermissionGroup(); } public String getUrlName() { diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties new file mode 100644 index 000000000..01aab6402 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties @@ -0,0 +1,20 @@ +# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # +# Copyright (c) 2014, 6WIND S.A. All rights reserved. # +# # +# This file is part of the Jenkins Lockable Resources Plugin and is # +# published under the MIT license. # +# # +# See the "LICENSE.txt" file for more information. # +# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # + +LockableResourcesRootAction.PermissionGroup=Ressources Verrouillables +LockableResourcesRootAction.UnlockPermission=D\u00e9verrouiller +LockableResourcesRootAction.UnlockPermission.Description=Cette autorisation donne la possibilit\u00e9 de manuellement \ + d\u00e9verrouiller des ressources qui ont \u00e9t\u00e9 verrouill\u00e9es par des constructions. +LockableResourcesRootAction.ReservePermission=R\u00e9server +LockableResourcesRootAction.ReservePermission.Description=Cette autorisation donne la possibilit\u00e9 de manuellement \ + r\u00e9server une ressource verrouillable en dehors d'une construction. +LockableResourcesRootAction.ViewPermission=Visualiser +LockableResourcesRootAction.ViewPermission.Description=Cette autorisation donne la possibilit\u00e9 de visualiser \ + les ressources verrouillables. + From 0b92085447171fa632d8c80ee9f50b8b56771cd7 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Mon, 13 Apr 2020 10:55:30 +0200 Subject: [PATCH 0063/1078] Adding skipIfLocked option to lock step (#184) I previously proposed a `tryLock`-step in #179. This fulfills that requirement with the `lock`-step by adding the option to not wait queue but instead skip the execution of the body. ```groovy lock(resource: 'some_resource', skipIfLocked: true) { echo 'Do something now!' } ``` --- README.md | 14 +++++++ .../plugins/lockableresources/LockStep.java | 7 ++++ .../lockableresources/LockStepExecution.java | 37 +++++++++++++------ .../LockableResourcesManager.java | 17 +++++++-- .../lockableresources/LockStep/config.jelly | 3 ++ .../LockStep/help-skipIfLocked.html | 8 ++++ .../lockableresources/LockStepTest.java | 24 +++++++++++- 7 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-skipIfLocked.html diff --git a/README.md b/README.md index 796c47976..0bdb081fa 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ them. Examples: +*Acquire lock* + ```groovy echo 'Starting' lock('my-resource-name') { @@ -54,6 +56,8 @@ lock('my-resource-name') { echo 'Finish' ``` +*Take first position in queue* + ```groovy lock(resource: 'staging-server', inversePrecedence: true) { node { @@ -63,12 +67,22 @@ lock(resource: 'staging-server', inversePrecedence: true) { } ``` +*Resolve a variable configured with the resource* + ```groovy lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { echo env.LOCKED_RESOURCE } ``` +*Skip executing the block if there is a queue* + +```groovy +lock(resource: 'some_resource', skipIfLocked: true) { + echo 'Do something now or never!' +} +``` + Detailed documentation can be found as part of the [Pipeline Steps](https://jenkins.io/doc/pipeline/steps/lockable-resources/) documentation. diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 2a8755100..98955ef8e 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -34,6 +34,8 @@ public class LockStep extends Step implements Serializable { public boolean inversePrecedence = false; + public boolean skipIfLocked = false; + @CheckForNull public List extra = null; // it should be LockStep() - without params. But keeping this for backward compatibility @@ -51,6 +53,11 @@ public void setInversePrecedence(boolean inversePrecedence) { this.inversePrecedence = inversePrecedence; } + @DataBoundSetter + public void setSkipIfLocked(boolean skipIfLocked) { + this.skipIfLocked = skipIfLocked; + } + @DataBoundSetter public void setLabel(String label) { if (label != null && !label.isEmpty()) { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 1a3dc1945..700722d50 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -1,9 +1,5 @@ package org.jenkins.plugins.lockableresources; -import com.google.common.base.Joiner; -import hudson.EnvVars; -import hudson.model.Run; -import hudson.model.TaskListener; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; @@ -12,6 +8,7 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; + import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; @@ -21,6 +18,12 @@ import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkinsci.plugins.workflow.support.actions.PauseAction; +import com.google.common.base.Joiner; + +import hudson.EnvVars; +import hudson.model.Run; +import hudson.model.TaskListener; + public class LockStepExecution extends AbstractStepExecutionImpl implements Serializable { private static final long serialVersionUID = 1391734561272059623L; @@ -60,7 +63,8 @@ public boolean start() throws Exception { // determine if there are enough resources available to proceed Set available = - LockableResourcesManager.get().checkResourcesAvailability(resourceHolderList, logger, null); + LockableResourcesManager.get() + .checkResourcesAvailability(resourceHolderList, logger, null, step.skipIfLocked); Run run = getContext().get(Run.class); if (available == null || !LockableResourcesManager.get() @@ -73,14 +77,25 @@ public boolean start() throws Exception { step.inversePrecedence)) { // if the resource is known, we could output the active/blocking job/build LockableResource resource = LockableResourcesManager.get().fromName(step.resource); - if (resource != null && resource.getBuildName() != null) { - logger.println("[" + step + "] is locked by " + resource.getBuildName() + ", waiting..."); - + boolean buildNameKnown = resource != null && resource.getBuildName() != null; + if (step.skipIfLocked) { + if (buildNameKnown) { + logger.println( + "[" + step + "] is locked by " + resource.getBuildName() + ", skipping execution..."); + } else { + logger.println("[" + step + "] is locked, skipping execution..."); + } + getContext().onSuccess(null); + return true; } else { - logger.println("[" + step + "] is locked, waiting..."); + if (buildNameKnown) { + logger.println("[" + step + "] is locked by " + resource.getBuildName() + ", waiting..."); + } else { + logger.println("[" + step + "] is locked, waiting..."); + } + LockableResourcesManager.get() + .queueContext(getContext(), resourceHolderList, step.toString(), step.variable); } - LockableResourcesManager.get() - .queueContext(getContext(), resourceHolderList, step.toString(), step.variable); } // proceed is called inside lock if execution is possible return false; } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index f5bf2645a..52cec6501 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -411,7 +411,7 @@ public synchronized void unlock( } } - this.unlockNames(resourceNamesToUnLock, build, inversePrecedence); + this.unlockNames(resourceNamesToUnLock, build, inversePrecedence); } public synchronized void unlockNames( @@ -733,6 +733,16 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti return true; } + /** @see #checkResourcesAvailability(List, PrintStream, List, boolean) */ + public synchronized Set checkResourcesAvailability( + List requiredResourcesList, + @Nullable PrintStream logger, + @Nullable List lockedResourcesAboutToBeUnlocked) { + boolean skipIfLocked = false; + return this.checkResourcesAvailability( + requiredResourcesList, logger, lockedResourcesAboutToBeUnlocked, skipIfLocked); + } + /** * Checks if there are enough resources available to satisfy the requirements specified within * requiredResources and returns the necessary available resources. If not enough resources are @@ -741,7 +751,8 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti public synchronized Set checkResourcesAvailability( List requiredResourcesList, @Nullable PrintStream logger, - @Nullable List lockedResourcesAboutToBeUnlocked) { + @Nullable List lockedResourcesAboutToBeUnlocked, + boolean skipIfLocked) { List requiredResourcesCandidatesList = new ArrayList<>(); @@ -832,7 +843,7 @@ public synchronized Set checkResourcesAvailability( } if (selected.size() < requiredAmount) { - if (logger != null) { + if (logger != null && !skipIfLocked) { logger.println( "Found " + selected.size() diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly index 1faabfafd..6dd385d99 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config.jelly @@ -16,6 +16,9 @@ + + +
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-skipIfLocked.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-skipIfLocked.html new file mode 100644 index 000000000..1a9e52762 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-skipIfLocked.html @@ -0,0 +1,8 @@ +
+

+ By default waiting builds get the lock. +

+

+ By checking this option the body will not be executed if there is a queue. It will only take the lock if it can be taken immediately. +

+
diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index c00cda224..345e1fc79 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -7,7 +7,11 @@ import hudson.Functions; import hudson.Launcher; -import hudson.model.*; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import hudson.model.Result; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -599,6 +603,7 @@ public void lockWithLabelConcurrent() throws Exception { for (int i = 0; i < 50; i++) { Thread thread = new Thread() { + @Override public void run() { try { barrier.await(); @@ -954,4 +959,21 @@ public void lockWithInvalidLabel() throws Exception { j.assertLogContains("The label does not exist: invalidLabel", b1); isPaused(b1, 0, 0); } + + @Test + public void skipIfLocked() throws Exception { + LockableResourcesManager lm = LockableResourcesManager.get(); + lm.createResourceWithLabel("resource1", "label1"); + lm.reserve(Arrays.asList(lm.fromName("resource1")), "test"); + + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(resource: 'resource1', skipIfLocked: true) {\n" + " echo 'Running body'\n" + "}")); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("[resource1] is locked, skipping execution...", b1); + j.assertLogNotContains("Running body", b1); + } } From 2af147239346672b1f2e7fcad16fed6b782a27dc Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Mon, 13 Apr 2020 21:03:25 +0200 Subject: [PATCH 0064/1078] Sort test cases by job type (#193) --- ...ionTest.java => FreeStyleProjectTest.java} | 48 ++++-------- .../InteroperabilityTest.java | 57 ++++++++++++++ .../lockableresources/LockStepTest.java | 75 +------------------ .../LockableResourceManagerTest.java | 43 +++++++++++ 4 files changed, 119 insertions(+), 104 deletions(-) rename src/test/java/org/jenkins/plugins/lockableresources/{BasicIntegrationTest.java => FreeStyleProjectTest.java} (83%) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java diff --git a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java similarity index 83% rename from src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java rename to src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java index 5cc35dde4..4c372c986 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/BasicIntegrationTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java @@ -18,10 +18,10 @@ import hudson.model.queue.QueueTaskFuture; import hudson.security.ACL; import hudson.triggers.TimerTrigger; -import hudson.util.FormValidation; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import jenkins.model.Jenkins; import org.acegisecurity.context.SecurityContext; @@ -40,7 +40,7 @@ import org.jvnet.hudson.test.SleepBuilder; import org.jvnet.hudson.test.TestExtension; -public class BasicIntegrationTest { +public class FreeStyleProjectTest { @Rule public JenkinsRule j = new JenkinsRule(); @@ -146,37 +146,7 @@ public void configRoundTrip() throws Exception { assertNull(withScriptProp.getLabelName()); assertNotNull(withScriptProp.getResourceMatchScript()); assertEquals("return true", withScriptProp.getResourceMatchScript().getScript()); - assertEquals(false, withScriptProp.getResourceMatchScript().isSandbox()); - } - - @Test - public void validationFailure() throws Exception { - RequiredResourcesProperty.DescriptorImpl d = new RequiredResourcesProperty.DescriptorImpl(); - LockableResourcesManager.get().createResource("resource1"); - LockableResource r = LockableResourcesManager.get().getResources().get(0); - r.setLabels("some-label"); - - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", null, true).getMessage()); - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", "some-label", false).getMessage()); - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", "some-label", true).getMessage()); - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", "resource1", false).getMessage()); - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", null, true).getMessage()); - assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", "resource1", true).getMessage()); - - assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false)); - assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false)); + assertFalse(withScriptProp.getResourceMatchScript().isSandbox()); } @Test @@ -243,6 +213,18 @@ public void approvalRequired() throws Exception { j.assertBuildStatusSuccess(futureBuild); } + @Test + public void autoCreateResource() throws IOException, InterruptedException, ExecutionException { + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + + FreeStyleBuild fb1 = f.scheduleBuild2(0).waitForStart(); + j.waitForMessage("acquired lock on [resource1]", fb1); + j.waitForCompletion(fb1); + + assertNull(LockableResourcesManager.get().fromName("resource1")); + } + @TestExtension public static class PrinterBuilder extends MockBuilder { diff --git a/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java new file mode 100644 index 000000000..fabb67c3f --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java @@ -0,0 +1,57 @@ +package org.jenkins.plugins.lockableresources; + +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import java.io.IOException; +import java.util.concurrent.Semaphore; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestBuilder; + +public class InteroperabilityTest extends LockStepTestBase { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Test + public void interoperability() throws Exception { + final Semaphore semaphore = new Semaphore(1); + LockableResourcesManager.get().createResource("resource1"); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock('resource1') {\n" + " echo 'Locked'\n" + "}\n" + "echo 'Finish'")); + + FreeStyleProject f = j.createFreeStyleProject("f"); + f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + f.getBuildersList() + .add( + new TestBuilder() { + + @Override + public boolean perform( + AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { + semaphore.acquire(); + return true; + } + }); + semaphore.acquire(); + FreeStyleBuild f1 = f.scheduleBuild2(0).waitForStart(); + + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("[resource1] is locked by " + f1.getFullDisplayName() + ", waiting...", b1); + isPaused(b1, 1, 1); + semaphore.release(); + + // Wait for lock after the freestyle finishes + j.waitForMessage("Lock released on resource [resource1]", b1); + isPaused(b1, 1, 0); + } +} diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 345e1fc79..e2e960abb 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -6,18 +6,11 @@ import static org.junit.Assume.assumeFalse; import hudson.Functions; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.FreeStyleBuild; -import hudson.model.FreeStyleProject; import hudson.model.Result; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.Semaphore; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; @@ -26,7 +19,6 @@ import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestBuilder; import org.jvnet.hudson.test.recipes.WithPlugin; public class LockStepTest extends LockStepTestBase { @@ -47,30 +39,6 @@ public void autoCreateResource() throws Exception { assertNull(LockableResourcesManager.get().fromName("resource1")); } - @Test - public void autoCreateResourceFreeStyle() throws IOException, InterruptedException { - FreeStyleProject f = j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); - - f.scheduleBuild2(0); - - while (j.jenkins.getQueue().getItems().length != 1) { - System.out.println("Waiting for freestyle to be queued..."); - Thread.sleep(1000); - } - - FreeStyleBuild fb1 = null; - while ((fb1 = f.getBuildByNumber(1)) == null) { - System.out.println("Waiting for freestyle #1 to start building..."); - Thread.sleep(1000); - } - - j.waitForMessage("acquired lock on [resource1]", fb1); - j.waitForCompletion(fb1); - - assertNull(LockableResourcesManager.get().fromName("resource1")); - } - @Test public void lockNothing() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); @@ -366,45 +334,8 @@ public void parallelLock() throws Exception { assertNotNull(LockableResourcesManager.get().fromName("resource1")); } - @Test - public void interoperability() throws Exception { - final Semaphore semaphore = new Semaphore(1); - LockableResourcesManager.get().createResource("resource1"); - WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition( - new CpsFlowDefinition( - "lock('resource1') {\n" + " echo 'Locked'\n" + "}\n" + "echo 'Finish'")); - - FreeStyleProject f = j.createFreeStyleProject("f"); - f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); - f.getBuildersList() - .add( - new TestBuilder() { - - @Override - public boolean perform( - AbstractBuild build, Launcher launcher, BuildListener listener) - throws InterruptedException, IOException { - semaphore.acquire(); - return true; - } - }); - semaphore.acquire(); - FreeStyleBuild f1 = f.scheduleBuild2(0).waitForStart(); - - WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); - j.waitForMessage("[resource1] is locked by " + f1.getFullDisplayName() + ", waiting...", b1); - isPaused(b1, 1, 1); - semaphore.release(); - - // Wait for lock after the freestyle finishes - j.waitForMessage("Lock released on resource [resource1]", b1); - isPaused(b1, 1, 0); - } - // TODO: Figure out what to do about the IOException thrown during clean up, since we don't care - // about it. It's just - // a result of the first build being deleted and is nothing but noise here. + // about it. It's just a result of the first build being deleted and is nothing but noise here. @Issue("JENKINS-36479") @Test public void deleteRunningBuildNewBuildClearsLock() throws Exception { @@ -969,7 +900,9 @@ public void skipIfLocked() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock(resource: 'resource1', skipIfLocked: true) {\n" + " echo 'Running body'\n" + "}")); + "lock(resource: 'resource1', skipIfLocked: true) {\n" + + " echo 'Running body'\n" + + "}")); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java new file mode 100644 index 000000000..946a824ab --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java @@ -0,0 +1,43 @@ +package org.jenkins.plugins.lockableresources; + +import static org.junit.Assert.assertEquals; + +import hudson.util.FormValidation; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class LockableResourceManagerTest { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Test + public void validationFailure() { + RequiredResourcesProperty.DescriptorImpl d = new RequiredResourcesProperty.DescriptorImpl(); + LockableResourcesManager.get().createResource("resource1"); + LockableResource r = LockableResourcesManager.get().getResources().get(0); + r.setLabels("some-label"); + + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", null, true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", "some-label", false).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckResourceNames("resource1", "some-label", true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", "resource1", false).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", null, true).getMessage()); + assertEquals( + "Only label, groovy expression, or resources can be defined, not more than one.", + d.doCheckLabelName("some-label", "resource1", true).getMessage()); + + assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false)); + assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false)); + } +} From 21cb4315c5abe032f4aa4f65e7e76d5439d3c272 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Tue, 14 Apr 2020 18:16:34 +0200 Subject: [PATCH 0065/1078] Cleanup some more deprecated constructs (#194) --- .../BackwardCompatibility.java | 17 +++++++----- .../plugins/lockableresources/LockStep.java | 2 +- .../lockableresources/LockStepExecution.java | 16 ++++-------- .../lockableresources/LockableResource.java | 17 ++++++++---- .../LockableResourcesManager.java | 26 +++++++++++-------- .../RequiredResourcesProperty.java | 16 +++++------- .../actions/LockableResourcesRootAction.java | 18 +++++-------- .../LockableResourcesQueueTaskDispatcher.java | 12 ++++----- .../queue/LockableResourcesStruct.java | 6 +++-- .../lockableresources/queue/Utils.java | 4 ++- .../FreeStyleProjectTest.java | 6 +---- 11 files changed, 71 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java index d990db53b..6cd3b2db5 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java @@ -11,20 +11,25 @@ import hudson.init.InitMilestone; import hudson.init.Initializer; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import org.jenkinsci.plugins.workflow.steps.StepContext; -import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; - import java.util.logging.Level; import java.util.logging.Logger; +import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; +import org.jenkinsci.plugins.workflow.steps.StepContext; +/** + * This class migrates "active" queuedContexts from LockableResource to LockableResourcesManager + * + * @deprecated Migration code for field introduced in 1.8 (since 1.11) + */ +@Deprecated public final class BackwardCompatibility { private static final Logger LOG = Logger.getLogger(BackwardCompatibility.class.getName()); + private BackwardCompatibility() {} + @Initializer(after = InitMilestone.JOB_LOADED) public static void compatibilityMigration() { LOG.log(Level.FINE, "lockable-resource-plugin compatibility migration task run"); @@ -42,4 +47,4 @@ public static void compatibilityMigration() { } } } -} \ No newline at end of file +} diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 98955ef8e..b80bf1cf7 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -124,7 +124,7 @@ public Set> getRequiredContext() { public String toString() { if (extra != null && !extra.isEmpty()) { return getResources().stream() - .map(resource -> "{" + resource.toString() + "}") + .map(res -> "{" + res.toString() + "}") .collect(Collectors.joining(",")); } else if (resource != null || label != null) { return LockStepResource.toString(resource, label, quantity); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 700722d50..ac7779caf 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -1,5 +1,8 @@ package org.jenkins.plugins.lockableresources; +import hudson.EnvVars; +import hudson.model.Run; +import hudson.model.TaskListener; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; @@ -8,7 +11,6 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; - import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; @@ -18,19 +20,11 @@ import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkinsci.plugins.workflow.support.actions.PauseAction; -import com.google.common.base.Joiner; - -import hudson.EnvVars; -import hudson.model.Run; -import hudson.model.TaskListener; - public class LockStepExecution extends AbstractStepExecutionImpl implements Serializable { private static final long serialVersionUID = 1391734561272059623L; - private static Joiner COMMA_JOINER = Joiner.on(','); - - private static Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); + private static final Logger LOGGER = Logger.getLogger(LockStepExecution.class.getName()); private final LockStep step; @@ -137,7 +131,7 @@ public static void proceed( @Override public void expand(EnvVars env) throws IOException, InterruptedException { - final String resources = COMMA_JOINER.join(resourcenames); + final String resources = String.join(",", resourcenames); LOGGER.finest( "Setting [" + variable diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index ae7fb96e5..9d3637755 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -67,9 +67,12 @@ public class LockableResource extends AbstractDescribableImpl * Was used within the initial implementation of Pipeline functionality using {@link LockStep}, * but became deprecated once several resources could be locked at once. See queuedContexts in * {@link LockableResourcesManager}. + * + * @deprecated Replaced with LockableResourcesManager.queuedContexts (since 1.11) */ @Deprecated private List queuedContexts = new ArrayList<>(); + /** @deprecated Use single-argument constructor instead (since 1.8) */ @Deprecated public LockableResource(String name, String description, String labels, String reservedBy) { this.name = name; @@ -83,13 +86,14 @@ public LockableResource(String name) { this.name = name; } - private Object readResolve() { + protected Object readResolve() { if (queuedContexts == null) { // this field was added after the initial version if this class queuedContexts = new ArrayList<>(); } return this; } + /** @deprecated Replaced with LockableResourcesManager.queuedContexts (since 1.11) */ @Deprecated public List getQueuedContexts() { return this.queuedContexts; @@ -160,8 +164,7 @@ public boolean scriptMatches( binding.setVariable("resourceDescription", description); binding.setVariable("resourceLabels", makeLabelsList()); try { - Object result = - script.evaluate(Jenkins.getInstance().getPluginManager().uberClassLoader, binding); + Object result = script.evaluate(Jenkins.get().getPluginManager().uberClassLoader, binding); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine( "Checked resource " @@ -194,7 +197,7 @@ public boolean isReserved() { public String getReservedByEmail() { if (reservedBy != null) { UserProperty email = null; - User user = Jenkins.getInstance().getUser(reservedBy); + User user = Jenkins.get().getUser(reservedBy); if (user != null) email = user.getProperty(UserProperty.class); if (email != null) return email.getAddress(); } @@ -252,7 +255,11 @@ public String getLockCause() { return build; } - /** @see WithBridgeMethods */ + /** + * @see WithBridgeMethods + * @deprecated Return value of {@link #getBuild()} was widened from AbstractBuild to Run (since + * 1.8) + */ @Deprecated private Object getAbstractBuild(final Run owner, final Class targetClass) { return owner instanceof AbstractBuild ? (AbstractBuild) owner : null; diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 52cec6501..15758266c 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -24,7 +24,6 @@ import jenkins.model.GlobalConfiguration; import jenkins.model.Jenkins; import net.sf.json.JSONObject; -import org.apache.commons.lang.StringUtils; import org.jenkins.plugins.lockableresources.queue.LockableResourcesCandidatesStruct; import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct; @@ -36,8 +35,11 @@ @Extension public class LockableResourcesManager extends GlobalConfiguration { + /** @deprecated Leftover of queue sorter support (since 1.7) */ @Deprecated private transient int defaultPriority; + /** @deprecated Leftover of queue sorter support (since 1.7) */ @Deprecated private transient String priorityParameterName; + private List resources; /** @@ -164,7 +166,7 @@ public List getResourcesWithLabel(String label, Map getResourcesMatchingScript( @@ -232,7 +234,7 @@ public synchronized List queue( * still waiting for the resources * @throws ExecutionException Cannot queue the resource due to the execution failure. Carries info * in the cause - * @since TODO + * @since 2.0 */ @CheckForNull public synchronized List tryQueue( @@ -255,7 +257,7 @@ public synchronized List tryQueue( } boolean candidatesByScript = false; - List candidates = new ArrayList<>(); + List candidates; final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); if (requiredResources.label != null && requiredResources.label.isEmpty() @@ -583,7 +585,9 @@ public synchronized boolean createResourceWithLabel(String name, String label) { if (name != null && label != null) { LockableResource existent = fromName(name); if (existent == null) { - getResources().add(new LockableResource(name, "", label, null)); + LockableResource resource = new LockableResource(name); + resource.setLabels(label); + getResources().add(resource); save(); return true; } @@ -630,9 +634,10 @@ public synchronized void unreserve(List resources) { if (nextContext == null) { LOGGER.log( Level.FINER, - "No context queued for resources " - + StringUtils.join(resourceNamesToUnreserve, ", ") - + " so unreserving and proceeding."); + () -> + "No context queued for resources " + + String.join(", ", resourceNamesToUnreserve) + + " so unreserving and proceeding."); unreserveResources(resources); return; } @@ -719,8 +724,7 @@ public synchronized void reset(List resources) { @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { - BulkChange bc = new BulkChange(this); - try { + try (BulkChange bc = new BulkChange(this)) { // reset resources to default which are not currently locked this.resources.removeIf(resource -> !resource.isLocked()); req.bindJSON(this, json); @@ -894,7 +898,7 @@ public synchronized boolean unqueueContext(StepContext context) { public static LockableResourcesManager get() { return (LockableResourcesManager) - Jenkins.getInstance().getDescriptorOrDie(LockableResourcesManager.class); + Jenkins.get().getDescriptorOrDie(LockableResourcesManager.class); } @Override diff --git a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java index 93f65dd32..dae310c75 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java @@ -12,24 +12,20 @@ import hudson.Util; import hudson.model.AbstractProject; import hudson.model.AutoCompletionCandidates; +import hudson.model.Job; import hudson.model.JobProperty; import hudson.model.JobPropertyDescriptor; -import hudson.model.Job; import hudson.util.FormValidation; - import java.util.ArrayList; import java.util.List; - +import javax.annotation.CheckForNull; import net.sf.json.JSONObject; - import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; -import javax.annotation.CheckForNull; - public class RequiredResourcesProperty extends JobProperty> { private final String resourceNames; @@ -43,7 +39,7 @@ public RequiredResourcesProperty(String resourceNames, String resourceNamesVar, String resourceNumber, String labelName, @CheckForNull SecureGroovyScript resourceMatchScript) { super(); - + if (resourceNames == null || resourceNames.trim().isEmpty()) { this.resourceNames = null; } else { @@ -73,6 +69,9 @@ public RequiredResourcesProperty(String resourceNames, } } + /** + * @deprecated groovy script was added (since 2.0) + */ @Deprecated public RequiredResourcesProperty(String resourceNames, String resourceNamesVar, String resourceNumber, @@ -118,7 +117,7 @@ public String getLabelName() { /** * Gets a system Groovy script to be executed in order to determine if the {@link LockableResource} matches the condition. * @return System Groovy Script if defined - * @since TODO + * @since 2.0 * @see LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, java.util.Map) */ @CheckForNull @@ -273,4 +272,3 @@ public static AutoCompletionCandidates doAutoCompleteResourceNames( } } } - diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 6f121181c..34835fd84 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -15,16 +15,12 @@ import hudson.security.Permission; import hudson.security.PermissionGroup; import hudson.security.PermissionScope; - import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; - import javax.servlet.ServletException; - import jenkins.model.Jenkins; - import org.jenkins.plugins.lockableresources.LockableResource; import org.jenkins.plugins.lockableresources.LockableResourcesManager; import org.jenkins.plugins.lockableresources.Messages; @@ -53,7 +49,7 @@ public class LockableResourcesRootAction implements RootAction { public static final String ICON = "/plugin/lockable-resources/img/device-24x24.png"; public String getIconFileName() { - return (Jenkins.getInstance().hasPermission(VIEW)) ? ICON : null; + return (Jenkins.get().hasPermission(VIEW)) ? ICON : null; } public String getUserName() { @@ -69,7 +65,7 @@ public String getDisplayName() { } public String getUrlName() { - return (Jenkins.getInstance().hasPermission(VIEW)) ? "lockable-resources" : ""; + return (Jenkins.get().hasPermission(VIEW)) ? "lockable-resources" : ""; } public List getResources() { @@ -90,7 +86,7 @@ public int getNumberOfAllLabels() { public void doUnlock(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - Jenkins.getInstance().checkPermission(UNLOCK); + Jenkins.get().checkPermission(UNLOCK); String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); @@ -108,7 +104,7 @@ public void doUnlock(StaplerRequest req, StaplerResponse rsp) public void doReserve(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - Jenkins.getInstance().checkPermission(RESERVE); + Jenkins.get().checkPermission(RESERVE); String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); @@ -128,7 +124,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) public void doUnreserve(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - Jenkins.getInstance().checkPermission(RESERVE); + Jenkins.get().checkPermission(RESERVE); String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); @@ -139,7 +135,7 @@ public void doUnreserve(StaplerRequest req, StaplerResponse rsp) String userName = getUserName(); if ((userName == null || !userName.equals(r.getReservedBy())) - && !Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER)) + && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)) throw new AccessDeniedException2(Jenkins.getAuthentication(), RESERVE); @@ -152,7 +148,7 @@ public void doUnreserve(StaplerRequest req, StaplerResponse rsp) public void doReset(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - Jenkins.getInstance().checkPermission(UNLOCK); + Jenkins.get().checkPermission(UNLOCK); String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java index ec8b25002..15c7ca9e7 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesQueueTaskDispatcher.java @@ -15,12 +15,11 @@ import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; import hudson.model.Job; +import hudson.model.ParameterValue; +import hudson.model.ParametersAction; import hudson.model.Queue; -import hudson.model.queue.QueueTaskDispatcher; import hudson.model.queue.CauseOfBlockage; -import hudson.model.ParametersAction; -import hudson.model.ParameterValue; - +import hudson.model.queue.QueueTaskDispatcher; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -29,7 +28,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; - import org.jenkins.plugins.lockableresources.LockableResource; import org.jenkins.plugins.lockableresources.LockableResourcesManager; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; @@ -161,7 +159,7 @@ public BecauseResourcesLocked(LockableResourcesStruct r) { @Override public String getShortDescription() { if (this.rscStruct.label.isEmpty()) { - if (this.rscStruct.required.size() > 0) { + if (!this.rscStruct.required.isEmpty()) { return "Waiting for resource instances " + rscStruct.required.toString(); } else { final SecureGroovyScript systemGroovyScript = this.rscStruct.getResourceMatchScript(); @@ -188,7 +186,7 @@ public String getShortDescription() { // Only for UI @Restricted(NoExternalUse.class) public static class BecauseResourcesQueueFailed extends CauseOfBlockage { - + @NonNull private final LockableResourcesStruct resources; @NonNull diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java index 269fa9103..49c809f0b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct.java @@ -107,8 +107,10 @@ public LockableResourcesStruct( * LockableResource} matches the condition. * * @return System Groovy Script if defined - * @see LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, java.util.Map) - * @since TODO + * @see + * LockableResource#scriptMatches(org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript, + * java.util.Map) + * @since 2.1 */ @CheckForNull public SecureGroovyScript getResourceMatchScript() { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/Utils.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/Utils.java index ccbf9040b..5fe180bc8 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/Utils.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/Utils.java @@ -16,8 +16,10 @@ import hudson.model.Run; import org.jenkins.plugins.lockableresources.RequiredResourcesProperty; -public class Utils { +public final class Utils { +private Utils() { +} public static Job getProject(Queue.Item item) { if (item.task instanceof Job) return (Job) item.task; diff --git a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java index 4c372c986..3a13c79cc 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java @@ -16,7 +16,6 @@ import hudson.model.Result; import hudson.model.User; import hudson.model.queue.QueueTaskFuture; -import hudson.security.ACL; import hudson.triggers.TimerTrigger; import java.io.IOException; import java.util.ArrayList; @@ -24,8 +23,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import jenkins.model.Jenkins; -import org.acegisecurity.context.SecurityContext; -import org.acegisecurity.context.SecurityContextHolder; import org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction; import org.jenkins.plugins.lockableresources.queue.LockableResourcesQueueTaskDispatcher; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; @@ -171,13 +168,12 @@ public void approvalRequired() throws Exception { "resourceName == org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction.ICON;"; FreeStyleProject p = j.createFreeStyleProject(); - SecurityContext orig = ACL.impersonate(User.get("alice").impersonate()); - SecurityContextHolder.setContext(orig); SecureGroovyScript groovyScript = new SecureGroovyScript(SCRIPT, true, null).configuring(ApprovalContext.create()); p.addProperty(new RequiredResourcesProperty(null, null, null, null, groovyScript)); + User.getOrCreateByIdOrFullName("alice"); JenkinsRule.WebClient wc = j.createWebClient(); wc.login("alice"); From b051df28569b4501ed7de20dcfeae235708c3ff7 Mon Sep 17 00:00:00 2001 From: akomakom Date: Thu, 23 Apr 2020 14:05:18 -0400 Subject: [PATCH 0066/1078] clarify context help for quantity (#199) --- .../plugins/lockableresources/LockStep/help-quantity.html | 1 + .../lockableresources/LockStepResource/help-quantity.html | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-quantity.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-quantity.html index 7646eb821..8eacc2342 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-quantity.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-quantity.html @@ -2,5 +2,6 @@

The quantity of resources with the specified label to be locked as defined in Global settings. Either a resource or a label need to be specified. + Empty value or 0 means lock all matching resources.

diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-quantity.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-quantity.html index 7646eb821..8eacc2342 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-quantity.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-quantity.html @@ -2,5 +2,6 @@

The quantity of resources with the specified label to be locked as defined in Global settings. Either a resource or a label need to be specified. + Empty value or 0 means lock all matching resources.

From cc6e4de846551f53c111e9ba50960f7835c51dc0 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 12:44:54 +0200 Subject: [PATCH 0067/1078] Update dependencies Dependencies are still very conservative and align with Jenkins 2.138.4. This allows use to remove a workaround for a bug in "retry()" (JENKINS-44379) and speeds up our tests as a side-effect :D --- .mvn/extensions.xml | 2 +- pom.xml | 16 ++++++++-------- .../lockableresources/LockStepHardKillTest.java | 5 ----- .../plugins/lockableresources/LockStepTest.java | 15 ++++++++------- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 94863e605..5f5104171 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-7 + 1.1 diff --git a/pom.xml b/pom.xml index 15a29644f..69d6eb8e4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 3.47 + 3.57 @@ -62,12 +62,12 @@ org.jenkins-ci.plugins structs - 1.18 + 1.20 org.jenkins-ci.plugins mailer - 1.13 + 1.18 org.jenkins-ci.plugins.workflow @@ -77,12 +77,12 @@ org.jenkins-ci.plugins matrix-project - 1.4 + 1.14 org.jenkins-ci.plugins script-security - 1.39 + 1.62 com.infradna.tool @@ -108,19 +108,19 @@ org.jenkins-ci.plugins.workflow workflow-basic-steps - 2.2 + 2.16 test org.jenkins-ci.plugins.workflow workflow-cps - 2.14 + 2.74 test org.jenkins-ci.plugins.workflow workflow-job - 2.0 + 2.38 test diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index fb700aa61..90a73eceb 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -155,11 +155,6 @@ private void interruptTermKill(WorkflowRun b) throws Exception { Executor ex = b.getExecutor(); assertNotNull(ex); ex.interrupt(); - j.waitForMessage("Click here to forcibly terminate running steps", b); - b.doTerm(); - j.waitForMessage("Click here to forcibly kill entire build", b); - b.doKill(); - j.waitForMessage("Hard kill!", b); j.waitForCompletion(b); j.assertBuildStatus(Result.ABORTED, b); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index e2e960abb..b3b32e077 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -302,14 +302,13 @@ public void lockInverseOrder() throws Exception { @Test public void parallelLock() throws Exception { - LockableResourcesManager.get().createResource("resource1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "parallel a: {\n" + " sleep 5\n" + " lock('resource1') {\n" - + " sleep 5\n" + + " semaphore 'inside-a'\n" + " }\n" + "}, b: {\n" + " lock('resource1') {\n" @@ -321,17 +320,19 @@ public void parallelLock() throws Exception { SemaphoreStep.waitForStart("wait-b/1", b1); // both messages are in the log because branch b acquired the lock and branch a is waiting to // lock - j.waitForMessage("[b] Lock acquired on [resource1]", b1); - j.waitForMessage( - "[a] [resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); + j.waitForMessage("Lock acquired on [resource1]", b1); + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); isPaused(b1, 2, 1); SemaphoreStep.success("wait-b/1", null); - j.waitForMessage("[a] Lock acquired on [resource1]", b1); + j.waitForMessage("Lock acquired on [resource1]", b1); + SemaphoreStep.waitForStart("inside-a/1", b1); isPaused(b1, 2, 0); + SemaphoreStep.success("inside-a/1", null); - assertNotNull(LockableResourcesManager.get().fromName("resource1")); + j.waitForCompletion(b1); + assertNull(LockableResourcesManager.get().fromName("resource1")); } // TODO: Figure out what to do about the IOException thrown during clean up, since we don't care From 847d93cd255ceaf13ee035d89232fb5ddd5a5636 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 15:50:00 +0200 Subject: [PATCH 0068/1078] Use script sandbox for all pipeline tests --- .../InteroperabilityTest.java | 2 +- .../LockStepHardKillTest.java | 7 +- .../lockableresources/LockStepTest.java | 114 ++++++++++-------- .../LockStepWithRestartTest.java | 14 +-- 4 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java index fabb67c3f..6e3ef5663 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java @@ -26,7 +26,7 @@ public void interoperability() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " echo 'Locked'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " echo 'Locked'\n" + "}\n" + "echo 'Finish'", true)); FreeStyleProject f = j.createFreeStyleProject("f"); f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index 90a73eceb..38cd2d8de 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -24,14 +24,15 @@ public void hardKillNewBuildClearsLock() throws Exception { WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p"); p1.setDefinition( - new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); + new CpsFlowDefinition( + "lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }", true)); WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); j.waitForMessage("locked!", b1); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( - new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); // Make sure that b2 is blocked on b1's lock. @@ -42,7 +43,7 @@ public void hardKillNewBuildClearsLock() throws Exception { // lock. WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( - new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index b3b32e077..3be44716b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -30,7 +30,7 @@ public void autoCreateResource() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " echo 'Resource locked'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " echo 'Resource locked'\n" + "}\n" + "echo 'Finish'", true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); @@ -44,7 +44,7 @@ public void lockNothing() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock() {\n" + " echo 'Nothing locked.'\n" + "}\n" + "echo 'Finish'")); + "lock() {\n" + " echo 'Nothing locked.'\n" + "}\n" + "echo 'Finish'", true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); @@ -60,7 +60,8 @@ public void lockWithLabel() throws Exception { "lock(label: 'label1', variable: 'var') {\n" + " echo \"Resource locked: ${env.var}\"\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); @@ -82,7 +83,8 @@ public void lockOrderLabel() throws Exception { "lock(label: 'label1', quantity: 2) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -128,7 +130,8 @@ public void lockOrderLabelQuantity() throws Exception { "lock(label: 'label1', quantity: 2) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -144,7 +147,8 @@ public void lockOrderLabelQuantity() throws Exception { "lock(label: 'label1', quantity: 1) {\n" + " semaphore 'wait-inside-quantity1'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); // While 2 continues waiting, 3 can continue directly SemaphoreStep.waitForStart("wait-inside-quantity1/1", b3); @@ -177,7 +181,8 @@ public void lockOrderLabelQuantityFreedResources() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock(label: 'label1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'")); + "lock(label: 'label1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -187,7 +192,8 @@ public void lockOrderLabelQuantityFreedResources() throws Exception { "lock(label: 'label1', quantity: 2) {\n" + " semaphore 'wait-inside-quantity2'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); // Ensure that b2 reaches the lock before b3 j.waitForMessage("[Label: label1, Quantity: 2] is locked, waiting...", b2); @@ -200,7 +206,8 @@ public void lockOrderLabelQuantityFreedResources() throws Exception { "lock(label: 'label1', quantity: 1) {\n" + " semaphore 'wait-inside-quantity1'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); j.waitForMessage("[Label: label1, Quantity: 1] is locked, waiting...", b3); j.waitForMessage("Found 0 available resource(s). Waiting for correct amount: 1.", b3); @@ -233,7 +240,8 @@ public void lockOrder() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -271,7 +279,8 @@ public void lockInverseOrder() throws Exception { "lock(resource: 'resource1', inversePrecedence: true) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -314,7 +323,8 @@ public void parallelLock() throws Exception { + " lock('resource1') {\n" + " semaphore 'wait-b'\n" + " }\n" - + "}\n")); + + "}\n", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-b/1", b1); @@ -346,20 +356,21 @@ public void deleteRunningBuildNewBuildClearsLock() throws Exception { WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p"); p1.setDefinition( - new CpsFlowDefinition("lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }")); + new CpsFlowDefinition( + "lock('resource1') { echo 'locked!'; semaphore 'wait-inside' }", true)); WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); j.waitForMessage("locked!", b1); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( - new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the lock. WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( - new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}")); + new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); // Make sure that b2 is blocked on b1's lock. @@ -530,7 +541,8 @@ public void lockWithLabelConcurrent() throws Exception { + " echo 'Resource locked'\n" + " sleep random.nextInt(10)*100\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); final CyclicBarrier barrier = new CyclicBarrier(51); for (int i = 0; i < 50; i++) { Thread thread = @@ -560,14 +572,16 @@ public void lockMultipleResources() throws Exception { "lock(resource: 'resource1', extra: [[resource: 'resource2']]) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); @@ -575,7 +589,8 @@ public void lockMultipleResources() throws Exception { WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( new CpsFlowDefinition( - "lock('resource2') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'")); + "lock('resource2') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource2] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); @@ -608,14 +623,16 @@ public void lockWithLabelAndResource() throws Exception { "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); @@ -623,10 +640,8 @@ public void lockWithLabelAndResource() throws Exception { WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( new CpsFlowDefinition( - "lock(label: 'label1') {\n" - + " semaphore 'wait-inside-p3'\n" - + "}\n" - + "echo 'Finish'")); + "lock(label: 'label1') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); j.waitForMessage("[Label: label1] is locked, waiting...", b3); isPaused(b3, 1, 1); @@ -659,14 +674,16 @@ public void lockWithLabelAndLabeledResource() throws Exception { "lock(label: 'label1', extra: [[resource: 'resource1']]) {\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside-p2'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); isPaused(b2, 1, 1); @@ -674,10 +691,8 @@ public void lockWithLabelAndLabeledResource() throws Exception { WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( new CpsFlowDefinition( - "lock(label: 'label1') {\n" - + " semaphore 'wait-inside-p3'\n" - + "}\n" - + "echo 'Finish'")); + "lock(label: 'label1') {\n" + " semaphore 'wait-inside-p3'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); j.waitForMessage("[Label: label1] is locked, waiting...", b3); isPaused(b3, 1, 1); @@ -712,12 +727,12 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { p.setDefinition( new CpsFlowDefinition( "lock(variable: 'var', extra: [[resource: 'resource4'], [resource: 'resource2'], [label: 'label1', quantity: 2]]) {\n" - + " def lockedResources = env.var.split(',')\n" - + " Arrays.sort(lockedResources)\n" + + " def lockedResources = env.var.split(',').sort()\n" + " echo \"Resources locked: ${lockedResources}\"\n" + " semaphore 'wait-inside'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); // #1 should lock as few resources as possible WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -726,12 +741,12 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { p2.setDefinition( new CpsFlowDefinition( "lock(label: 'label1', variable: 'var', quantity: 3) {\n" - + " def lockedResources = env.var.split(',')\n" - + " Arrays.sort(lockedResources)\n" + + " def lockedResources = env.var.split(',').sort()\n" + " echo \"Resources locked: ${lockedResources}\"\n" + " semaphore 'wait-inside-quantity3'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); j.waitForMessage("[Label: label1, Quantity: 3] is locked, waiting...", b2); j.waitForMessage("Found 2 available resource(s). Waiting for correct amount: 3.", b2); @@ -741,12 +756,12 @@ public void lockWithLabelAndLabeledResourceQuantity() throws Exception { p3.setDefinition( new CpsFlowDefinition( "lock(label: 'label1', variable: 'var', quantity: 2) {\n" - + " def lockedResources = env.var.split(',')\n" - + " Arrays.sort(lockedResources)\n" + + " def lockedResources = env.var.split(',').sort()\n" + " echo \"Resources locked: ${lockedResources}\"\n" + " semaphore 'wait-inside-quantity2'\n" + "}\n" - + "echo 'Finish'")); + + "echo 'Finish'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); // While 2 continues waiting, 3 can continue directly SemaphoreStep.waitForStart("wait-inside-quantity2/1", b3); @@ -787,7 +802,8 @@ public void lockWithLabelFillsVariable() throws Exception { "lock(label: 'label1', variable: 'someVar') {\n" + " semaphore 'wait-inside'\n" + " echo \"VAR IS $env.someVar\"\n" - + "}")); + + "}", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -796,7 +812,8 @@ public void lockWithLabelFillsVariable() throws Exception { new CpsFlowDefinition( "lock(label: 'label1', variable: 'someVar2') {\n" + " echo \"VAR2 IS $env.someVar2\"\n" - + "}")); + + "}", + true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); j.waitForMessage("is locked, waiting...", b2); isPaused(b2, 1, 1); @@ -834,7 +851,8 @@ public void parallelLockWithLabelFillsVariable() throws Exception { + " lock(label: 'label1', variable: 'someVar2') {\n" + " echo \"VAR2 IS $env.someVar2\"\n" + " }\n" - + "}")); + + "}", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-outside/1", b1); SemaphoreStep.waitForStart("wait-inside/1", b1); @@ -869,7 +887,8 @@ public void unreserveSetsVariable() throws Exception { new CpsFlowDefinition( "lock(label: 'label1', variable: 'someVar') {\n" + " echo \"VAR IS $env.someVar\"\n" - + "}")); + + "}", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForMessage("is locked, waiting...", b1); @@ -884,7 +903,7 @@ public void unreserveSetsVariable() throws Exception { public void lockWithInvalidLabel() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition("lock(label: 'invalidLabel') {\n" + "}\n")); + p.setDefinition(new CpsFlowDefinition("lock(label: 'invalidLabel') {\n" + "}\n", true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.FAILURE, b1); @@ -901,9 +920,8 @@ public void skipIfLocked() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock(resource: 'resource1', skipIfLocked: true) {\n" - + " echo 'Running body'\n" - + "}")); + "lock(resource: 'resource1', skipIfLocked: true) {\n" + " echo 'Running body'\n" + "}", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.SUCCESS, b1); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 38491e276..aaa6f02c9 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -33,10 +33,8 @@ public void lockOrderRestart() { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}\n" - + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); WorkflowRun b2 = p.scheduleBuild2(0).waitForStart(); @@ -86,10 +84,8 @@ public void interoperabilityOnRestart() { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" - + " semaphore 'wait-inside'\n" - + "}\n" - + "echo 'Finish'")); + "lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}\n" + "echo 'Finish'", + true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); isPaused(b1, 1, 0); @@ -136,7 +132,7 @@ public void testReserveOverRestart() { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + " echo 'inside'\n" + "}\n" + "echo 'Finish'")); + "lock('resource1') {\n" + " echo 'inside'\n" + "}\n" + "echo 'Finish'", true)); WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked, waiting...", b1); isPaused(b1, 1, 1); From d410c91e67d09de7fc23f04589ad6f009cc6a873 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 16:31:21 +0200 Subject: [PATCH 0069/1078] Sleep less in tests Replace most places where sleep was used before with semaphores. This should speed up tests a bit and should also make them more reliable & deterministic. --- .../FreeStyleProjectTest.java | 70 +++++++++++-------- .../lockableresources/LockStepTest.java | 4 +- .../LockStepWithRestartTest.java | 19 ++--- .../lockableresources/TestHelpers.java | 37 ++++++++++ 4 files changed, 88 insertions(+), 42 deletions(-) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java diff --git a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java index 3a13c79cc..40317c1e5 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java @@ -1,5 +1,8 @@ package org.jenkins.plugins.lockableresources; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -17,6 +20,7 @@ import hudson.model.User; import hudson.model.queue.QueueTaskFuture; import hudson.triggers.TimerTrigger; +import hudson.util.OneShotEvent; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -30,12 +34,7 @@ import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; import org.junit.Rule; import org.junit.Test; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.MockAuthorizationStrategy; -import org.jvnet.hudson.test.MockBuilder; -import org.jvnet.hudson.test.SleepBuilder; -import org.jvnet.hudson.test.TestExtension; +import org.jvnet.hudson.test.*; public class FreeStyleProjectTest { @@ -73,19 +72,23 @@ public void migrateToScript() throws Exception { assertNotNull(newProp.getResourceMatchScript()); assertEquals("resourceName == 'resource1'", newProp.getResourceMatchScript().getScript()); - p2.getBuildersList().add(new SleepBuilder(5000)); + SemaphoreBuilder p2Builder = new SemaphoreBuilder(); + p2.getBuildersList().add(p2Builder); FreeStyleProject p3 = j.createFreeStyleProject("p3"); p3.addProperty(new RequiredResourcesProperty("resource1", null, "1", null, null)); - p3.getBuildersList().add(new SleepBuilder(10000)); + SemaphoreBuilder p3Builder = new SemaphoreBuilder(); + p3.getBuildersList().add(p3Builder); final QueueTaskFuture taskA = p3.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); - Thread.sleep(2500); + TestHelpers.waitForQueue(j.jenkins, p3); final QueueTaskFuture taskB = p2.scheduleBuild2(0, new TimerTrigger.TimerTriggerCause()); + p3Builder.release(); final FreeStyleBuild buildA = taskA.get(60, TimeUnit.SECONDS); + p2Builder.release(); final FreeStyleBuild buildB = taskB.get(60, TimeUnit.SECONDS); long buildAEndTime = buildA.getStartTimeInMillis() + buildA.getDuration(); @@ -99,7 +102,7 @@ public void migrateToScript() throws Exception { } @Test - public void configRoundTrip() throws Exception { + public void configRoundTripPlain() throws Exception { LockableResourcesManager.get().createResource("resource1"); FreeStyleProject withResource = j.createFreeStyleProject("withResource"); @@ -115,7 +118,10 @@ public void configRoundTrip() throws Exception { assertNull(withResourceProp.getResourceNumber()); assertNull(withResourceProp.getLabelName()); assertNull(withResourceProp.getResourceMatchScript()); + } + @Test + public void configRoundTripWithLabel() throws Exception { FreeStyleProject withLabel = j.createFreeStyleProject("withLabel"); withLabel.addProperty(new RequiredResourcesProperty(null, null, null, "some-label", null)); FreeStyleProject withLabelRoundTrip = j.configRoundtrip(withLabel); @@ -128,7 +134,10 @@ public void configRoundTrip() throws Exception { assertNull(withLabelProp.getResourceNumber()); assertEquals("some-label", withLabelProp.getLabelName()); assertNull(withLabelProp.getResourceMatchScript()); + } + @Test + public void configRoundTripWithScript() throws Exception { FreeStyleProject withScript = j.createFreeStyleProject("withScript"); SecureGroovyScript origScript = new SecureGroovyScript("return true", false, null); withScript.addProperty(new RequiredResourcesProperty(null, null, null, null, origScript)); @@ -178,20 +187,12 @@ public void approvalRequired() throws Exception { wc.login("alice"); QueueTaskFuture futureBuild = p.scheduleBuild2(0); + TestHelpers.waitForQueue(j.jenkins, p, Queue.BlockedItem.class); - // Sleeping briefly to make sure the queue gets updated. - Thread.sleep(2000); - - List items = j.jenkins.getQueue().getItems(p); - assertNotNull(items); - assertEquals(1, items.size()); - - assertTrue(items.get(0) instanceof Queue.BlockedItem); - - Queue.BlockedItem blockedItem = (Queue.BlockedItem) items.get(0); - assertTrue( - blockedItem.getCauseOfBlockage() - instanceof LockableResourcesQueueTaskDispatcher.BecauseResourcesQueueFailed); + Queue.BlockedItem blockedItem = (Queue.BlockedItem) j.jenkins.getQueue().getItem(p); + assertThat( + blockedItem.getCauseOfBlockage(), + is(instanceOf(LockableResourcesQueueTaskDispatcher.BecauseResourcesQueueFailed.class))); ScriptApproval approval = ScriptApproval.get(); List pending = new ArrayList<>(); @@ -221,12 +222,7 @@ public void autoCreateResource() throws IOException, InterruptedException, Execu assertNull(LockableResourcesManager.get().fromName("resource1")); } - @TestExtension - public static class PrinterBuilder extends MockBuilder { - - public PrinterBuilder() { - super(Result.SUCCESS); - } + public static class PrinterBuilder extends TestBuilder { @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) @@ -237,4 +233,20 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen return true; } } + + private static class SemaphoreBuilder extends TestBuilder { + + private final OneShotEvent event = new OneShotEvent(); + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException { + event.block(); + return true; + } + + void release() { + event.signal(); + } + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 3be44716b..fbc5a133f 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -315,7 +315,7 @@ public void parallelLock() throws Exception { p.setDefinition( new CpsFlowDefinition( "parallel a: {\n" - + " sleep 5\n" + + " semaphore 'before-a'\n" + " lock('resource1') {\n" + " semaphore 'inside-a'\n" + " }\n" @@ -328,9 +328,11 @@ public void parallelLock() throws Exception { WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-b/1", b1); + SemaphoreStep.waitForStart("before-a/1", b1); // both messages are in the log because branch b acquired the lock and branch a is waiting to // lock j.waitForMessage("Lock acquired on [resource1]", b1); + SemaphoreStep.success("before-a/1", null); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b1); isPaused(b1, 2, 1); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index aaa6f02c9..997455088 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -94,11 +94,7 @@ public void interoperabilityOnRestart() { f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); f.scheduleBuild2(0); - - while (j.jenkins.getQueue().getItems().length != 1) { - System.out.println("Waiting for freestyle to be queued..."); - Thread.sleep(1000); - } + TestHelpers.waitForQueue(j.jenkins, f); }); story.then( @@ -111,11 +107,14 @@ public void interoperabilityOnRestart() { SemaphoreStep.success("wait-inside/1", null); j.waitForMessage("Lock released on resource [resource1]", b1); isPaused(b1, 1, 0); + FreeStyleBuild fb1 = null; + System.out.print("Waiting for freestyle #1 to start building"); while ((fb1 = f.getBuildByNumber(1)) == null) { - System.out.println("Waiting for freestyle #1 to start building..."); - Thread.sleep(1000); + Thread.sleep(250); + System.out.print('.'); } + System.out.println(); j.waitForMessage("acquired lock on [resource1]", fb1); }); @@ -141,11 +140,7 @@ public void testReserveOverRestart() { f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); f.scheduleBuild2(0); - - while (j.jenkins.getQueue().getItems().length != 1) { - System.out.println("Waiting for freestyle to be queued..."); - Thread.sleep(1000); - } + TestHelpers.waitForQueue(j.jenkins, f); }); story.then( diff --git a/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java new file mode 100644 index 000000000..d116e7e11 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT + * Copyright (c) 2020, Tobias Gruetzmacher + */ +package org.jenkins.plugins.lockableresources; + +import hudson.model.FreeStyleProject; +import hudson.model.Queue; +import jenkins.model.Jenkins; + +public final class TestHelpers { + + private static final int SLEEP_TIME = 100; + private static final int MAX_WAIT = 5000; + + // Utility class + private TestHelpers() {} + + public static void waitForQueue(Jenkins jenkins, FreeStyleProject job) + throws InterruptedException { + waitForQueue(jenkins, job, Queue.Item.class); + } + + /** Schedule a build and make sure it has been added to Jenkins' queue. */ + public static void waitForQueue(Jenkins jenkins, FreeStyleProject job, Class itemType) + throws InterruptedException { + System.out.print("Waiting for job to be queued..."); + int waitTime = 0; + while (!itemType.isInstance(jenkins.getQueue().getItem(job)) && waitTime < MAX_WAIT) { + Thread.sleep(SLEEP_TIME); + waitTime += SLEEP_TIME; + if (waitTime % 1000 == 0) { + System.out.print(" " + waitTime / 1000 + "s"); + } + } + System.out.println(); + } +} From e3958742cec24a93c7f85383098f4bfe08880149 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 17:14:37 +0200 Subject: [PATCH 0070/1078] Fix a possible race condition in a test --- .../plugins/lockableresources/LockStepTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index fbc5a133f..92f65812a 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -368,16 +368,16 @@ public void deleteRunningBuildNewBuildClearsLock() throws Exception { p2.setDefinition( new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); + // Make sure that b2 is blocked on b1's lock. + j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); + isPaused(b2, 1, 1); - // Now b2 is still sitting waiting for a lock. Create b3 and launch it to clear the lock. + // Now b2 is still sitting waiting for a lock. Create b3 and launch it to verify order of + // unlock. WorkflowJob p3 = j.jenkins.createProject(WorkflowJob.class, "p3"); p3.setDefinition( new CpsFlowDefinition("lock('resource1') {\n" + " semaphore 'wait-inside'\n" + "}", true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); - - // Make sure that b2 is blocked on b1's lock. - j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b2); - isPaused(b2, 1, 1); j.waitForMessage("[resource1] is locked by " + b1.getFullDisplayName() + ", waiting...", b3); isPaused(b3, 1, 1); From 43eaf765bb6429976abe3017532c9423558dc13f Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 17:17:04 +0200 Subject: [PATCH 0071/1078] Run all tests on Java 11+ This problem was probably fixed by dependency updates. --- .../lockableresources/LockStepWithRestartTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java index 997455088..99e11bb5b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepWithRestartTest.java @@ -1,7 +1,5 @@ package org.jenkins.plugins.lockableresources; -import static org.junit.Assume.assumeFalse; - import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import java.util.Collections; @@ -9,7 +7,6 @@ import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -19,12 +16,6 @@ public class LockStepWithRestartTest extends LockStepTestBase { @Rule public RestartableJenkinsRule story = new RestartableJenkinsRule(); - @Before - public void disableOnNewerJava() { - // FIXME: These tests break on Java 11 - assumeFalse(Double.parseDouble(System.getProperty("java.specification.version", "1.8")) > 10.0); - } - @Test public void lockOrderRestart() { story.then( From 59fb4749a389e133e5775786f592bfe1129c27fe Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 22:10:50 +0200 Subject: [PATCH 0072/1078] Document test failure on Windows --- .../plugins/lockableresources/LockStepTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 92f65812a..ef966f0ee 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -347,12 +347,20 @@ public void parallelLock() throws Exception { assertNull(LockableResourcesManager.get().fromName("resource1")); } - // TODO: Figure out what to do about the IOException thrown during clean up, since we don't care - // about it. It's just a result of the first build being deleted and is nothing but noise here. + /* TODO: This test does not run on Windows. Before wasting another afternoon trying to fix this, I'd suggest watching + * a good movie instead. If you really want to try your luck, here are some pointers: + * - Windows doesn't like to delete files that are currently in use + * - When deleting a running pipeline job, the listener keeps its logfile open + * This has the potential to fail at two points: + * - Right when deleting the run: Jenkins tries to remove the run directory, which contains the open log file + * - After the test, on cleanup, the jenkins test harness tries to remove the complete Jenkins data directory + * Things already tried: Getting a handle on the listener and closing its logfile. + * Stupid idea: Implement a JEP-210 extension, which keeps log files in memory... + */ @Issue("JENKINS-36479") @Test public void deleteRunningBuildNewBuildClearsLock() throws Exception { - assumeFalse(Functions.isWindows()); // TODO: Investigate failure on Windows. + assumeFalse(Functions.isWindows()); LockableResourcesManager.get().createResource("resource1"); From 2aef91c31a024f57fd878f7d512262de8a38a162 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 26 Apr 2020 23:39:07 +0200 Subject: [PATCH 0073/1078] Test API return values --- .../lockableresources/LockableResources.java | 18 +++++------ .../lockableresources/LockStepTest.java | 10 ++++++ .../lockableresources/TestHelpers.java | 31 +++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResources.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResources.java index 321de3453..2c6ba6ad9 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResources.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResources.java @@ -10,24 +10,20 @@ import hudson.Plugin; import hudson.model.Api; - import java.util.Collections; import java.util.List; - import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; @ExportedBean public class LockableResources extends Plugin { - public Api getApi() { - return new Api(this); - } - - @Exported - public List getResources() { - return Collections.unmodifiableList(LockableResourcesManager.get() - .getResources()); - } + public Api getApi() { + return new Api(this); + } + @Exported + public List getResources() { + return Collections.unmodifiableList(LockableResourcesManager.get().getResources()); + } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index ef966f0ee..9a27be8db 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -1,5 +1,7 @@ package org.jenkins.plugins.lockableresources; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasEntry; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -11,6 +13,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CyclicBarrier; +import net.sf.json.JSONObject; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; @@ -186,6 +189,9 @@ public void lockOrderLabelQuantityFreedResources() throws Exception { WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-inside/1", b1); + JSONObject apiRes = TestHelpers.getResourceFromApi(j, "resource1", true); + assertThat(apiRes, hasEntry("labels", "label1")); + WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( new CpsFlowDefinition( @@ -494,6 +500,10 @@ public void manualUnreserveUnblocksJob() throws Exception { resource1.setReservedBy("someone"); assertTrue(resource1.isReserved()); + JSONObject apiRes = TestHelpers.getResourceFromApi(j, "resource1", false); + assertThat(apiRes, hasEntry("reserved", true)); + assertThat(apiRes, hasEntry("reservedBy", "someone")); + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( diff --git a/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java index d116e7e11..844995f4b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java @@ -3,9 +3,16 @@ */ package org.jenkins.plugins.lockableresources; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + import hudson.model.FreeStyleProject; import hudson.model.Queue; +import java.io.IOException; import jenkins.model.Jenkins; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.jvnet.hudson.test.JenkinsRule; public final class TestHelpers { @@ -34,4 +41,28 @@ public static void waitForQueue(Jenkins jenkins, FreeStyleProject job, Class } System.out.println(); } + + /** + * Get a resource from the JSON API and validate some basic properties. This allows to verify that + * the API returns sane values while running other tests. + */ + public static JSONObject getResourceFromApi( + JenkinsRule rule, String resourceName, boolean isLocked) throws IOException { + JSONObject data = getApiData(rule); + JSONArray resources = data.getJSONArray("resources"); + assertThat(resources, is(not(nullValue()))); + JSONObject res = + (JSONObject) + (resources.stream() + .filter(e -> resourceName.equals(((JSONObject) e).getString("name"))) + .findAny() + .orElseThrow( + () -> new AssertionError("Could not find '" + resourceName + "' in API."))); + assertThat(res, hasEntry("locked", isLocked)); + return res; + } + + public static JSONObject getApiData(JenkinsRule rule) throws IOException { + return rule.getJSON("plugin/lockable-resources/api/json").getJSONObject(); + } } From b7ec81a3056419046fd0ed708cbd7130be212d0e Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Mon, 27 Apr 2020 00:23:19 +0200 Subject: [PATCH 0074/1078] [maven-release-plugin] prepare release lockable-resources-2.8 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 69d6eb8e4..e34ca35fd 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - ${revision}${changelist} + 2.8 hpi Lockable Resources plugin @@ -46,7 +46,7 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - ${scmTag} + lockable-resources-2.8 From 11ea53b66dcbd87fa8da3b95ecf54bd2a466ea97 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Mon, 27 Apr 2020 00:23:35 +0200 Subject: [PATCH 0075/1078] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index e34ca35fd..7babe0c8b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - 2.8 + ${revision}${changelist} hpi Lockable Resources plugin @@ -46,11 +46,11 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - lockable-resources-2.8 + ${scmTag} - 2.8 + 2.9 -SNAPSHOT 8 3.4 From 0a6851dcc4af66d035b1a99c59aca046bf46785c Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Sun, 10 May 2020 20:57:31 +0200 Subject: [PATCH 0076/1078] Update slf4j to allow builds against recent Jenkins LTS --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index 7babe0c8b..8cd6dbb31 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,8 @@ 3.4 2.138.4 1.25 + + 1.7.26 From d607ebfffb5c344d435fb72cc17ffc058bd271fe Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 7 Aug 2020 00:14:32 +0200 Subject: [PATCH 0077/1078] Replace "recommended" CI configurations with fixed configurations --- Jenkinsfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 64ffb54d2..6421eda0a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,7 @@ #!groovy -buildPlugin(configurations: buildPlugin.recommendedConfigurations()) - +def recentLTS = "2.222.4" +buildPlugin(configurations: [ + [ platform: "linux", jdk: "8", jenkins: null ], + [ platform: "windows", jdk: "8", jenkins: recentLTS, javaLevel: "8" ], + [ platform: "linux", jdk: "11", jenkins: recentLTS, javaLevel: "8" ], +]) From 50ab82498f792775a761e6f4937607b240ecde67 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 18 Sep 2020 22:04:05 +0200 Subject: [PATCH 0078/1078] [SECURITY-1958] --- .../actions/LockableResourcesRootAction.java | 5 ++ .../LockableResourcesRootAction/index.jelly | 10 +++- .../lockableresources/LockStepTest.java | 7 +-- .../LockableResourceApiTest.java | 47 +++++++++++++++++++ .../lockableresources/TestHelpers.java | 19 ++++++++ 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockableResourceApiTest.java diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 34835fd84..917ebd0eb 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -26,6 +26,7 @@ import org.jenkins.plugins.lockableresources.Messages; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.interceptor.RequirePOST; @Extension public class LockableResourcesRootAction implements RootAction { @@ -84,6 +85,7 @@ public int getNumberOfAllLabels() { return LockableResourcesManager.get().getAllLabels().size(); } + @RequirePOST public void doUnlock(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Jenkins.get().checkPermission(UNLOCK); @@ -102,6 +104,7 @@ public void doUnlock(StaplerRequest req, StaplerResponse rsp) rsp.forwardToPreviousPage(req); } + @RequirePOST public void doReserve(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Jenkins.get().checkPermission(RESERVE); @@ -122,6 +125,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) rsp.forwardToPreviousPage(req); } + @RequirePOST public void doUnreserve(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Jenkins.get().checkPermission(RESERVE); @@ -146,6 +150,7 @@ public void doUnreserve(StaplerRequest req, StaplerResponse rsp) rsp.forwardToPreviousPage(req); } + @RequirePOST public void doReset(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Jenkins.get().checkPermission(UNLOCK); diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index bf63dba59..8a5ddec66 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -1,6 +1,6 @@ 1.7.26 + 2.67 From 66b6bab6857c27d88ade0c155e8c89a1f566cbe1 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 25 Sep 2020 20:44:59 +0200 Subject: [PATCH 0082/1078] Update test LTS version to 2.249.1 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6421eda0a..a9761a45d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ #!groovy -def recentLTS = "2.222.4" +def recentLTS = "2.249.1" buildPlugin(configurations: [ [ platform: "linux", jdk: "8", jenkins: null ], [ platform: "windows", jdk: "8", jenkins: recentLTS, javaLevel: "8" ], From 08427e9bb34396e6b81a2205323ec979d73e2304 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 25 Sep 2020 20:50:33 +0200 Subject: [PATCH 0083/1078] Move JavaScript to its own file This restores button functionality for Jenkins >= 2.246. I never realized the previous code put the script block OUTSIDE the tag, which breaks the DOM in horrible and unintended ways. --- .../LockableResourcesRootAction/index.jelly | 19 ++----------------- src/main/webapp/js/lockable-resources.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 src/main/webapp/js/lockable-resources.js diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 8a5ddec66..e443b7013 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -9,24 +9,9 @@ --> - - +

${%Lockable Resources}

diff --git a/src/main/webapp/js/lockable-resources.js b/src/main/webapp/js/lockable-resources.js new file mode 100644 index 000000000..2ec317a4e --- /dev/null +++ b/src/main/webapp/js/lockable-resources.js @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2020, Tobias Gruetzmacher + +function find_resource_name(element) { + var row = element.up('tr'); + var resourceName = row.getAttribute('data-resource-name'); + return resourceName; +} + +function resource_action(button, action) { + // TODO: Migrate to form:link after Jenkins 2.233 (for button-styled links) + var form = document.createElement('form'); + form.setAttribute('method', 'POST'); + form.setAttribute('action', action + "?resource=" + find_resource_name(button)); + crumb.appendToForm(form); + document.body.appendChild(form); + form.submit(); +} From b4397e8dd76609235a7284db8579c8b730155b02 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 25 Sep 2020 22:37:07 +0200 Subject: [PATCH 0084/1078] [maven-release-plugin] prepare release lockable-resources-2.10 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a7213d8e1..c2c193002 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - ${revision}${changelist} + 2.10 hpi Lockable Resources plugin @@ -46,7 +46,7 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - ${scmTag} + lockable-resources-2.10 From 094568f3dde3b2a4b0d263c8afa90bcc0cac7a57 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Fri, 25 Sep 2020 22:37:21 +0200 Subject: [PATCH 0085/1078] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c2c193002..8ad545526 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - 2.10 + ${revision}${changelist} hpi Lockable Resources plugin @@ -46,11 +46,11 @@ scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git https://github.com/jenkinsci/lockable-resources-plugin - lockable-resources-2.10 + ${scmTag} - 2.10 + 2.11 -SNAPSHOT 8 3.4 From 721d11648807ee99e802fef80c47ca71ebcadbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Prislan?= Date: Wed, 30 Dec 2020 11:43:58 +0100 Subject: [PATCH 0086/1078] * added button to copy resource name to clipboard --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index e443b7013..3aa6f3eb6 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -28,7 +28,7 @@ From 9721834f3268d8f7797f18d9b24d59863192f7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Prislan?= Date: Wed, 30 Dec 2020 17:42:22 +0100 Subject: [PATCH 0087/1078] * added tooltip --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 3aa6f3eb6..22f83e5d5 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -28,7 +28,7 @@ From 796644751ec7999eb3bb313bfba665377a9f7215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Prislan?= Date: Thu, 31 Dec 2020 10:55:39 +0100 Subject: [PATCH 0088/1078] * added space to rerun checks on PR --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 22f83e5d5..670d5a1a1 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -28,7 +28,7 @@ From 55f9aabea4820f5b0891d133153de234f4ba1f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Prislan?= Date: Sat, 2 Jan 2021 17:20:10 +0100 Subject: [PATCH 0089/1078] * enable localizable messages (i18n) --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- .../actions/LockableResourcesRootAction/index.properties | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 670d5a1a1..b5648bd54 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -28,7 +28,7 @@ diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties new file mode 100644 index 000000000..e69de29bb From d992714d23f37f40013cfa13e05079fae889d528 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Thu, 18 Mar 2021 14:51:08 -0700 Subject: [PATCH 0090/1078] Update plugin metadata for 2021 (#233) --- .github/CODEOWNERS | 1 + .github/dependabot.yml | 16 ++++++++ .github/release-drafter.yml | 1 + .github/workflows/release-drafter.yml | 17 +++++++++ .mvn/extensions.xml | 2 +- Jenkinsfile | 21 +++++++--- pom.xml | 55 ++++++++++++++------------- 7 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..fb83349a8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @jenkinsci/lockable-resources-plugin-developers diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..2ec774af6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "daily" + reviewers: + - "basil" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + reviewers: + - "basil" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 155554f31..c6beb6411 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,2 +1,3 @@ +# https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc _extends: .github tag-template: lockable-resources-$NEXT_MINOR_VERSION diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 000000000..b99da970d --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,17 @@ +# Automates creation of Release Drafts using Release Drafter +# More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc + +on: + push: + branches: + - master + - main + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into the default branch + - uses: release-drafter/release-drafter@v5.13.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 5f5104171..43d628161 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.1 + 1.2 diff --git a/Jenkinsfile b/Jenkinsfile index a9761a45d..bdd4061f4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,16 @@ -#!groovy -def recentLTS = "2.249.1" -buildPlugin(configurations: [ - [ platform: "linux", jdk: "8", jenkins: null ], - [ platform: "windows", jdk: "8", jenkins: recentLTS, javaLevel: "8" ], - [ platform: "linux", jdk: "11", jenkins: recentLTS, javaLevel: "8" ], +/* + * See the documentation for more options: + * https://github.com/jenkins-infra/pipeline-library/ + */ +buildPlugin(useAci: true, configurations: [ + // Test the long-term support end of the compatibility spectrum (i.e., the minimum required + // Jenkins version). + [ platform: 'linux', jdk: '8', jenkins: null ], + + // Test the common case (i.e., a recent LTS release) on both Linux and Windows. + [ platform: 'linux', jdk: '8', jenkins: '2.277.1' ], + [ platform: 'windows', jdk: '8', jenkins: '2.277.1' ], + + // Test the bleeding edge of the compatibility spectrum (i.e., the latest supported Java runtime). + [ platform: 'linux', jdk: '11', jenkins: '2.277.1' ], ]) diff --git a/pom.xml b/pom.xml index 8ad545526..225ebccf9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,11 @@ - + 4.0.0 org.jenkins-ci.plugins plugin - 3.57 + 4.17 @@ -20,7 +20,7 @@ computers) that can be used by builds. If a build requires an external resource which is already locked, it will wait for the resource to be free. - https://github.com/jenkinsci/lockable-resources-plugin + https://github.com/jenkinsci/${project.artifactId}-plugin 2013 @@ -30,6 +30,11 @@ + + basil + Basil Crow + me@basilcrow.com + TobiX Tobias Gruetzmacher @@ -43,9 +48,9 @@ - scm:git:https://github.com/jenkinsci/lockable-resources-plugin.git - scm:git:git@github.com:jenkinsci/lockable-resources-plugin.git - https://github.com/jenkinsci/lockable-resources-plugin + scm:git:git://github.com/${gitHubRepo}.git + scm:git:git@github.com:${gitHubRepo}.git + https://github.com/${gitHubRepo} ${scmTag} @@ -53,39 +58,42 @@ 2.11 -SNAPSHOT 8 - 3.4 - 2.138.4 - 1.25 - - 1.7.26 - 2.67 + 2.164.3 + jenkinsci/${project.artifactId}-plugin + + + + io.jenkins.tools.bom + bom-2.164.x + 10 + import + pom + + + + org.jenkins-ci.plugins structs - 1.20 org.jenkins-ci.plugins mailer - 1.18 org.jenkins-ci.plugins.workflow workflow-support - ${workflow-support.version} org.jenkins-ci.plugins matrix-project - 1.14 org.jenkins-ci.plugins script-security - 1.62 com.infradna.tool @@ -104,39 +112,32 @@ org.jenkins-ci.plugins.workflow workflow-support - ${workflow-support.version} tests test org.jenkins-ci.plugins.workflow workflow-basic-steps - 2.16 test org.jenkins-ci.plugins.workflow workflow-cps - 2.74 test org.jenkins-ci.plugins.workflow workflow-job - 2.38 test io.jenkins configuration-as-code - ${configuration-as-code.version} test - io.jenkins - configuration-as-code - ${configuration-as-code.version} - tests + io.jenkins.configuration-as-code + test-harness test @@ -160,7 +161,7 @@ com.coveo fmt-maven-plugin - 2.9 + 2.9.1 From 4ac525ba31f7c6e049a1d0aa3983b9ad96c5bdf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:52:04 +0000 Subject: [PATCH 0091/1078] Bump release-drafter/release-drafter from v5.13.0 to v5.15.0 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from v5.13.0 to v5.15.0. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/v5.13.0...fe52e97d262833ae07d05efaf1a239df3f1b5cd4) Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index b99da970d..f566bc2e8 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: runs-on: ubuntu-latest steps: # Drafts your next Release notes as Pull Requests are merged into the default branch - - uses: release-drafter/release-drafter@v5.13.0 + - uses: release-drafter/release-drafter@v5.15.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 6b845a58c85cd3866af356f79e755e1690b01158 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:52:12 +0000 Subject: [PATCH 0092/1078] Bump fmt-maven-plugin from 2.9.1 to 2.10 Bumps [fmt-maven-plugin](https://github.com/coveo/fmt-maven-plugin) from 2.9.1 to 2.10. - [Release notes](https://github.com/coveo/fmt-maven-plugin/releases) - [Commits](https://github.com/coveo/fmt-maven-plugin/compare/2.9.1...2.10.0) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 225ebccf9..0bd879947 100644 --- a/pom.xml +++ b/pom.xml @@ -161,7 +161,7 @@ com.coveo fmt-maven-plugin - 2.9.1 + 2.10 From d0279b44af851c83a204c953346c30c15b5fb30c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 1 Aug 2019 13:52:28 +0200 Subject: [PATCH 0093/1078] Fix jelly EBD lint errors, the EBD line should be first --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- .../actions/LockedResourcesBuildAction/index.jelly | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index e443b7013..02be50af9 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -1,3 +1,4 @@ + - + src="${resURL}/plugin/lockable-resources/js/lockable-resources.js"/>

${%Lockable Resources}

- ${resource.name} + ${resource.name}
${resource.description}
- ${resource.name} + ${resource.name}
${resource.description}
- ${resource.name} + ${resource.name}
${resource.description}
- ${resource.name} + ${resource.name}
${resource.description}
- + - - - - - + + + + + + + @@ -39,9 +41,13 @@ ${resource.build.fullDisplayName} + +
+ +
- + - + - + - + + + +
ResourceStatusLabelsEphemeralActionResourceStatusLabelsEphemeralAction
${resource.labels}${resource.ephemeral} @@ -57,9 +63,13 @@ RESERVED by ${resource.reservedBy} + +
+ +
${resource.labels}${resource.ephemeral} QUEUED by "${resource.queueItemProject} ${resource.queueItemId}" + +
+ +
${resource.labels}${resource.ephemeral} @@ -99,7 +113,7 @@ FREE ${resource.labels}${resource.ephemeral} @@ -109,6 +123,29 @@
+ +
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/noteForm.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/noteForm.jelly new file mode 100644 index 000000000..799ccc171 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/noteForm.jelly @@ -0,0 +1,49 @@ + + + + + + + + + + +
+
+ + + +
+
+ +
+
+
+
+
diff --git a/src/main/webapp/js/lockable-resources.js b/src/main/webapp/js/lockable-resources.js index 8280b84eb..771559571 100644 --- a/src/main/webapp/js/lockable-resources.js +++ b/src/main/webapp/js/lockable-resources.js @@ -16,3 +16,25 @@ function resource_action(button, action) { document.body.appendChild(form); form.submit(); } + +function replaceNote(element, resourceName) { + var d = document.getElementById("note-" + resourceName); + $(d).down().next().innerHTML = "
loading...
"; + new Ajax.Request( + "noteForm", + { + parameters: {resource: resourceName}, + onComplete : function(x) { + d.innerHTML = x.responseText; + evalInnerHtmlScripts(x.responseText,function() { + Behaviour.applySubtree(d); + d.getElementsByTagName("TEXTAREA")[0].focus(); + }); + layoutUpdateCallback.call(); + } + } + ); + return false; +} + + diff --git a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java index da2195d19..61f8528a3 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java @@ -34,6 +34,7 @@ public void should_support_configuration_as_code() { assertEquals("Description_A", declaredResource.getDescription()); assertEquals("Label_A", declaredResource.getLabels()); assertEquals("Reserved_A", declaredResource.getReservedBy()); + assertEquals("Note A", declaredResource.getNote()); List resources = LockableResourcesManager.get().getResources(); assertEquals( @@ -46,6 +47,7 @@ public void should_support_configuration_as_code() { assertEquals("Description_A", resource.getDescription()); assertEquals("Label_A", resource.getLabels()); assertEquals("Reserved_A", resource.getReservedBy()); + assertEquals("Note A", resource.getNote()); } @Test diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 120df4bcf..79ae64ae6 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -2,6 +2,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; +import static org.jenkins.plugins.lockableresources.TestHelpers.clickButton; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -501,7 +503,9 @@ public void manualUnreserveUnblocksJob() throws Exception { LockableResource resource1 = LockableResourcesManager.get().fromName("resource1"); assertNotNull(resource1); resource1.setReservedBy("someone"); + assertEquals("someone", resource1.getReservedBy()); assertTrue(resource1.isReserved()); + assertNull(resource1.getReservedTimestamp()); JSONObject apiRes = TestHelpers.getResourceFromApi(j, "resource1", false); assertThat(apiRes, hasEntry("reserved", true)); @@ -1005,13 +1009,13 @@ public void reserveInsideLockHonoured() throws Exception { + " echo \"Locked resource cause 2-2: ${lr.getLockCause()}\"\n" + " echo \"Locked resource reservedBy 2-2: ${lr.getReservedBy()}\"\n" + " echo \"Setting (directly) and dropping (via LRM) a reservation on locked resource\"\n" - + " lr.setReservedBy('test2-1')\n" + + " lr.reserve('test2-1')\n" + " sleep (3)\n" + " " + lmget + ".unreserve([lr])\n" + " echo \"Just sleeping...\"\n" + " sleep (20)\n" + " echo \"Setting (directly) a reservation on locked resource\"\n" - + " lr.setReservedBy('test2-2')\n" + + " lr.reserve('test2-2')\n" + " echo \"Unlocking parallel closure 2\"\n" + " }\n" + " echo \"Locked resource cause 2-3: ${lr.getLockCause()}\"\n" diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java index b8f5001f4..6824c6ca8 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceTest.java @@ -3,8 +3,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import java.util.Date; import org.junit.Test; public class LockableResourceTest { @@ -17,7 +19,9 @@ public void testGetters() { assertEquals("r1", instance.getName()); assertEquals("", instance.getDescription()); assertEquals("", instance.getLabels()); + assertEquals("", instance.getNote()); assertNull(instance.getReservedBy()); + assertNull(instance.getReservedTimestamp()); assertFalse(instance.isReserved()); assertFalse(instance.isQueued()); assertFalse(instance.isQueued(0)); @@ -28,6 +32,22 @@ public void testGetters() { assertNull(instance.getQueueItemProject()); } + @Test + public void testNote() { + final LockableResource resource = new LockableResource("Name 1"); + + assertEquals("", resource.getNote()); + + resource.setNote("Note 1"); + assertEquals("Note 1", resource.getNote()); + + resource.setNote("Note B"); + assertEquals("Note B", resource.getNote()); + + resource.setNote(""); + assertEquals("", resource.getNote()); + } + @Test public void testUnqueue() { instance.unqueue(); @@ -43,9 +63,28 @@ public void testSetReservedBy() { instance.setReservedBy(""); } + @Test + public void testReservedTimestamp() { + instance.setReservedTimestamp(null); + assertNull(instance.getReservedTimestamp()); + + final Date date = new Date(); + instance.setReservedTimestamp(date); + assertEquals(date, instance.getReservedTimestamp()); + } + + @Test + public void testReserve() { + instance.reserve("testUser1"); + assertEquals("testUser1", instance.getReservedBy()); + assertNotNull(instance.getReservedTimestamp()); + } + @Test public void testUnReserve() { instance.unReserve(); + assertNull(instance.getReservedBy()); + assertNull(instance.getReservedTimestamp()); } @Test diff --git a/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml b/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml index 3572a0f8f..50d19d666 100644 --- a/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml +++ b/src/test/resources/org/jenkins/plugins/lockableresources/casc_expected_output.yml @@ -2,4 +2,5 @@ declaredResources: - description: "Description_A" labels: "Label_A" name: "Resource_A" + note: "Note A" reservedBy: "Reserved_A" diff --git a/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml b/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml index 431776e0f..1690a7f8d 100644 --- a/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml +++ b/src/test/resources/org/jenkins/plugins/lockableresources/configuration-as-code.yml @@ -11,3 +11,4 @@ unclassified: labels: "Label_A" name: "Resource_A" reservedBy: "Reserved_A" + note: "Note A" From 6be9b3c6e446d419fa23483bfa9e2f8e5f02cfd8 Mon Sep 17 00:00:00 2001 From: offa Date: Wed, 2 Feb 2022 12:30:29 +0100 Subject: [PATCH 0181/1078] Add fallback if no timestamp --- .../jenkins/plugins/lockableresources/LockableResource.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 29f94ee2f..6f09f860b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -281,11 +281,12 @@ public boolean isLocked() { @CheckForNull public String getLockCause() { final DateFormat format = SimpleDateFormat.getDateTimeInstance(MEDIUM, SHORT); + final String timestamp = (reservedTimestamp == null ? "" : format.format(reservedTimestamp)); if (isReserved()) { - return String.format("[%s] is reserved by %s at %s", name, reservedBy, format.format(reservedTimestamp)); + return String.format("[%s] is reserved by %s at %s", name, reservedBy, timestamp); } if (isLocked()) { - return String.format("[%s] is locked by %s at %s", name, buildExternalizableId, format.format(reservedTimestamp)); + return String.format("[%s] is locked by %s at %s", name, buildExternalizableId, timestamp); } return null; } From e93d7af7c75dfe6db67be71b0e7b041a88484e40 Mon Sep 17 00:00:00 2001 From: offa Date: Wed, 2 Feb 2022 12:44:08 +0100 Subject: [PATCH 0182/1078] Remove unused import --- .../lockableresources/actions/LockableResourcesRootAction.java | 2 +- .../org/jenkins/plugins/lockableresources/LockStepTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index c893225e5..503206136 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -142,7 +142,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) if (!LockableResourcesManager.get().reserve(resources, userName)) { rsp.sendError(423, "Resource '" + name + "' already reserved or locked!"); return; - }; + } } rsp.forwardToPreviousPage(req); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 79ae64ae6..a8aec13ed 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -2,7 +2,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; -import static org.jenkins.plugins.lockableresources.TestHelpers.clickButton; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; From 4feaeb4de7a6fbfb38ba08425351d44137d3dd27 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Feb 2022 19:10:06 +0100 Subject: [PATCH 0183/1078] Update README.md: Refresh that there is a maintainer in 2022 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d47a3e403..7b5a4bb42 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/lockable-resources.svg?color=blue)](https://plugins.jenkins.io/lockable-resources) [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) [![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) -[![Maintenance](https://img.shields.io/maintenance/yes/2021.svg)](https://github.com/jenkinsci/lockable-resources-plugin) +[![Maintenance](https://img.shields.io/maintenance/yes/2022.svg)](https://github.com/jenkinsci/lockable-resources-plugin) This plugin allows defining lockable resources (such as printers, phones, computers, etc.) that can be used by builds. If a build requires a resource From d37edf5a6ff2fcd8d32d08467c0f415d2f562425 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Feb 2022 19:10:17 +0100 Subject: [PATCH 0184/1078] Update README.md: Refresh list of maintainers --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7b5a4bb42..b780f2cdb 100644 --- a/README.md +++ b/README.md @@ -151,5 +151,6 @@ The MIT License (MIT) - Copyright 2013-2015 6WIND - Copyright 2016-2018 Antonio Muñiz - Copyright 2019 TobiX +- Copyright 2017-2022 Jim Klimov See [LICENSE](LICENSE.txt) From 9af24b0fd900add03e1d90dcd086690fa1c95fba Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Feb 2022 20:28:57 +0100 Subject: [PATCH 0185/1078] Update LockableResourcesManager.java Fix merge error --- .../plugins/lockableresources/LockableResourcesManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 4e3b03d5b..968b4965b 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -274,11 +274,9 @@ public synchronized List tryQueue( return null; } - boolean candidatesByScript = false; - List candidates; final SecureGroovyScript systemGroovyScript = requiredResources.getResourceMatchScript(); boolean candidatesByScript = (systemGroovyScript != null); - List candidates = requiredResources.required; // default canditates + List candidates = requiredResources.required; // default candidates if (candidatesByScript || (requiredResources.label != null && !requiredResources.label.isEmpty())) { From adbbee3ed4912156e88288c17ed2b6f388cfb6f4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Feb 2022 20:47:50 +0100 Subject: [PATCH 0186/1078] LockableResourcesRootAction/index.jelly: lands on top --- .../actions/LockableResourcesRootAction/index.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index f0496eb65..f656bc6ac 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -1,3 +1,4 @@ + - - + ${resource.name}
${resource.description} - + LOCKED by @@ -46,20 +43,20 @@ - ${resource.labels} - - + ${resource.labels} + + - + - +
- + RESERVED by ${resource.reservedBy} @@ -68,23 +65,23 @@ - ${resource.labels} - - + ${resource.labels} + + - + -
+
-
+
@@ -93,30 +90,30 @@
- + QUEUED by "${resource.queueItemProject} ${resource.queueItemId}"
- ${resource.labels} - - + ${resource.labels} + + - +
- + FREE - ${resource.labels} - - + ${resource.labels} + + - + @@ -124,8 +121,8 @@
- -
+ +
@@ -150,27 +147,27 @@ -

Labels

- +

Labels

+
+ + + + - - - - - - + + - - + + - - + + From 8518f191a2eed494218041b0a26a46d0b8b0b7cf Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sat, 22 Oct 2022 20:17:29 +0200 Subject: [PATCH 0237/1078] Add a contributing guide (#364) --- CONTRIBUTING.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 42 ++++-------------------------------------- 2 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6482c1148 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ + +## Contributing + +If you want to contribute to this plugin, you probably will need a Jenkins plugin development +environment. This basically means a current version of Java (Java 8 should probably be okay for now) +and [Apache Maven]. See the [Jenkins Plugin Tutorial] for details. + +If you have the proper environment, typing: + + $ mvn verify + +should create a plugin as `target/*.hpi`, which you can install in your Jenkins instance. Running + + $ mvn hpi:run -Djenkins.version=2.249.1 + +allows you to spin up a test Jenkins instance on [localhost] to test your +local changes before committing. + +[Apache Maven]: https://maven.apache.org/ +[Jenkins Plugin Tutorial]: https://jenkins.io/doc/developer/tutorial/prepare/ +[localhost]: http://localhost:8080/jenkins/ + +### Code Style + +This plugin tries to migrate to [Google Java Code Style], please try to adhere to that style +whenever adding new files or making big changes to existing files. If your IDE doesn't support +this style, you can use the [fmt-maven-plugin], like this: + + $ mvn fmt:format -DfilesNamePattern=ChangedFile\.java + +to reformat Java code in the proper style. + +[Google Java Code Style]: https://google.github.io/styleguide/javaguide.html +[fmt-maven-plugin]: https://github.com/coveo/fmt-maven-plugin + +## License + +The MIT License (MIT) + +- Copyright 2013-2015 6WIND +- Copyright 2016-2018 Antonio Muñiz +- Copyright 2019 TobiX +- Copyright 2017-2022 Jim Klimov + +See [LICENSE](LICENSE.txt) diff --git a/README.md b/README.md index ee43a7cfb..90623afc3 100644 --- a/README.md +++ b/README.md @@ -129,45 +129,11 @@ unclassified: ## Contributing -If you want to contribute to this plugin, you probably will need a Jenkins plugin development -environment. This basically means a current version of Java (Java 8 should probably be okay for now) -and [Apache Maven]. See the [Jenkins Plugin Tutorial] for details. - -If you have the proper environment, typing: - - $ mvn verify - -should create a plugin as `target/*.hpi`, which you can install in your Jenkins instance. Running - - $ mvn hpi:run -Djenkins.version=2.249.1 - -allows you to spin up a test Jenkins instance on [localhost] to test your -local changes before committing. - -[Apache Maven]: https://maven.apache.org/ -[Jenkins Plugin Tutorial]: https://jenkins.io/doc/developer/tutorial/prepare/ -[localhost]: http://localhost:8080/jenkins/ - -### Code Style - -This plugin tries to migrate to [Google Java Code Style], please try to adhere to that style -whenever adding new files or making big changes to existing files. If your IDE doesn't support -this style, you can use the [fmt-maven-plugin], like this: - - $ mvn fmt:format -DfilesNamePattern=ChangedFile\.java - -to reformat Java code in the proper style. - -[Google Java Code Style]: https://google.github.io/styleguide/javaguide.html -[fmt-maven-plugin]: https://github.com/coveo/fmt-maven-plugin +Contributions are welcome, please +refer to the separate [CONTRIBUTING](CONTRIBUTING.md) document +for details on how to proceed! ## License -The MIT License (MIT) - -- Copyright 2013-2015 6WIND -- Copyright 2016-2018 Antonio Muñiz -- Copyright 2019 TobiX -- Copyright 2017-2022 Jim Klimov - +All source code is licensed under the MIT license. See [LICENSE](LICENSE.txt) From 98294a6660f5b1824a32705a364570e96bc65a4a Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 23 Oct 2022 14:02:55 +0200 Subject: [PATCH 0238/1078] Require 2.346.3 as minimum Jenkins version (#361) Update io.jenkins.tools.bom version --- Jenkinsfile | 7 ++++--- pom.xml | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8487bb01b..ce532703e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,9 +8,10 @@ buildPlugin(useContainerAgent: true, configurations: [ [ platform: 'linux', jdk: '8' ], // Test the common case (i.e., a recent LTS release) on both Linux and Windows. - [ platform: 'linux', jdk: '11', jenkins: '2.332.1' ], - [ platform: 'windows', jdk: '11', jenkins: '2.332.1' ], + [ platform: 'linux', jdk: '11', jenkins: '2.346.3' ], + [ platform: 'windows', jdk: '11', jenkins: '2.346.3' ], // Test the bleeding edge of the compatibility spectrum (i.e., the latest supported Java runtime). - [ platform: 'linux', jdk: '17', jenkins: '2.342' ], + // see also https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ + [ platform: 'linux', jdk: '17', jenkins: '2.361.1' ], ]) diff --git a/pom.xml b/pom.xml index 07b919a36..af56a3ef0 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 2.19 -SNAPSHOT - 2.289.3 + 2.346.3 jenkinsci/${project.artifactId}-plugin @@ -65,8 +65,8 @@ io.jenkins.tools.bom - bom-2.289.x - 1500.ve4d05cd32975 + bom-2.332.x + 1643.v1cffef51df73 import pom From ec35bc26e9de464faeae8a821b332348220b91c7 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:38:12 +0200 Subject: [PATCH 0239/1078] Paranoid security check (#363) eliminate issues found by Jenkins Security Scan. Some of these changes looks paranoid but it is the faster way to eliminate current security-check issues. --- .../plugins/lockableresources/LockStep.java | 23 ++++++--- .../lockableresources/LockStepResource.java | 27 +++++++--- .../RequiredResourcesProperty.java | 49 ++++++++++++++++--- .../LockableResourceManagerTest.java | 16 +++--- 4 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 49109c906..6a9cca988 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -5,6 +5,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; import hudson.Extension; import hudson.model.AutoCompletionCandidates; +import hudson.model.Item; import hudson.model.TaskListener; import hudson.util.FormValidation; import java.io.Serializable; @@ -17,9 +18,11 @@ import org.jenkinsci.plugins.workflow.steps.StepContext; import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import org.jenkinsci.plugins.workflow.steps.StepExecution; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.interceptor.RequirePOST; public class LockStep extends Step implements Serializable { @@ -103,18 +106,26 @@ public boolean takesImplicitBlockArgument() { return true; } - public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value) { - return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value); + @RequirePOST + public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value, + @AncestorInPath Item item) { + return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value, item); } + @RequirePOST public static FormValidation doCheckLabel( - @QueryParameter String value, @QueryParameter String resource) { - return LockStepResource.DescriptorImpl.doCheckLabel(value, resource); + @QueryParameter String value, + @QueryParameter String resource, + @AncestorInPath Item item) { + return LockStepResource.DescriptorImpl.doCheckLabel(value, resource, item); } + @RequirePOST public static FormValidation doCheckResource( - @QueryParameter String value, @QueryParameter String label) { - return LockStepResource.DescriptorImpl.doCheckLabel(label, value); + @QueryParameter String value, + @QueryParameter String label, + @AncestorInPath Item item) { + return LockStepResource.DescriptorImpl.doCheckLabel(label, value, item); } @Override diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java index 10ee64974..ecfe91e91 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java @@ -8,11 +8,14 @@ import hudson.model.AbstractDescribableImpl; import hudson.model.AutoCompletionCandidates; import hudson.model.Descriptor; +import hudson.model.Item; import hudson.util.FormValidation; import java.io.Serializable; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.interceptor.RequirePOST; public class LockStepResource extends AbstractDescribableImpl implements Serializable { @@ -100,11 +103,21 @@ public String getDisplayName() { return "Resource"; } - public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value) { - return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value); + @RequirePOST + public AutoCompletionCandidates doAutoCompleteResource(@QueryParameter String value, + @AncestorInPath Item item) { + return RequiredResourcesProperty.DescriptorImpl.doAutoCompleteResourceNames(value, item); } - public static FormValidation doCheckLabel(@QueryParameter String value, @QueryParameter String resource) { + @RequirePOST + public static FormValidation doCheckLabel(@QueryParameter String value, + @QueryParameter String resource, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } + String resourceLabel = Util.fixEmpty(value); String resourceName = Util.fixEmpty(resource); if (resourceLabel != null && resourceName != null) { @@ -119,9 +132,11 @@ public static FormValidation doCheckLabel(@QueryParameter String value, @QueryPa return FormValidation.ok(); } - public static FormValidation doCheckResource(@QueryParameter String value, @QueryParameter String label) { - return doCheckLabel(label, value); + @RequirePOST + public static FormValidation doCheckResource(@QueryParameter String value, + @QueryParameter String label, + @AncestorInPath Item item) { + return doCheckLabel(label, value, item); } } - } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java index c0599dae0..8a5afedb0 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java @@ -14,18 +14,22 @@ import hudson.Util; import hudson.model.AbstractProject; import hudson.model.AutoCompletionCandidates; +import hudson.model.Item; import hudson.model.Job; import hudson.model.JobProperty; import hudson.model.JobPropertyDescriptor; import hudson.util.FormValidation; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import net.sf.json.JSONObject; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.interceptor.RequirePOST; public class RequiredResourcesProperty extends JobProperty> { @@ -148,9 +152,16 @@ public RequiredResourcesProperty newInstance(StaplerRequest req, JSONObject form return null; } + @RequirePOST public FormValidation doCheckResourceNames(@QueryParameter String value, @QueryParameter String labelName, - @QueryParameter boolean script) { + @QueryParameter boolean script, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } + String labelVal = Util.fixEmptyAndTrim(labelName); String names = Util.fixEmptyAndTrim(value); @@ -183,10 +194,17 @@ public FormValidation doCheckResourceNames(@QueryParameter String value, } } + @RequirePOST public FormValidation doCheckLabelName( @QueryParameter String value, @QueryParameter String resourceNames, - @QueryParameter boolean script) { + @QueryParameter boolean script, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } + String label = Util.fixEmptyAndTrim(value); String names = Util.fixEmptyAndTrim(resourceNames); @@ -205,11 +223,16 @@ public FormValidation doCheckLabelName( } } + @RequirePOST public FormValidation doCheckResourceNumber(@QueryParameter String value, @QueryParameter String resourceNames, @QueryParameter String labelName, - @QueryParameter String resourceMatchScript) - { + @QueryParameter String resourceMatchScript, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } String number = Util.fixEmptyAndTrim(value); String names = Util.fixEmptyAndTrim(resourceNames); @@ -243,8 +266,15 @@ public FormValidation doCheckResourceNumber(@QueryParameter String value, return FormValidation.ok(); } + @RequirePOST public AutoCompletionCandidates doAutoCompleteLabelName( - @QueryParameter String value) { + @QueryParameter String value, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } + AutoCompletionCandidates c = new AutoCompletionCandidates(); value = Util.fixEmptyAndTrim(value); @@ -256,8 +286,15 @@ public AutoCompletionCandidates doAutoCompleteLabelName( return c; } + @RequirePOST public static AutoCompletionCandidates doAutoCompleteResourceNames( - @QueryParameter String value) { + @QueryParameter String value, + @AncestorInPath Item item) { + // check permission, security first + if (item != null) { + item.checkPermission(Item.CONFIGURE); + } + AutoCompletionCandidates c = new AutoCompletionCandidates(); value = Util.fixEmptyAndTrim(value); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java index 95b636625..905a28845 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java @@ -20,24 +20,24 @@ public void validationFailure() { assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", null, true).getMessage()); + d.doCheckResourceNames("resource1", null, true, null).getMessage()); assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", "some-label", false).getMessage()); + d.doCheckResourceNames("resource1", "some-label", false, null).getMessage()); assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckResourceNames("resource1", "some-label", true).getMessage()); + d.doCheckResourceNames("resource1", "some-label", true, null).getMessage()); assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", "resource1", false).getMessage()); + d.doCheckLabelName("some-label", "resource1", false, null).getMessage()); assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", null, true).getMessage()); + d.doCheckLabelName("some-label", null, true, null).getMessage()); assertEquals( "Only label, groovy expression, or resources can be defined, not more than one.", - d.doCheckLabelName("some-label", "resource1", true).getMessage()); + d.doCheckLabelName("some-label", "resource1", true, null).getMessage()); - assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false)); - assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false)); + assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false, null)); + assertEquals(FormValidation.ok(), d.doCheckLabelName("some-label", null, false, null)); } } From 20182cda348d0f6ff0703bfe1a253ddf650f110a Mon Sep 17 00:00:00 2001 From: Pokorny Martin Date: Wed, 26 Oct 2022 18:52:12 +0200 Subject: [PATCH 0240/1078] read for translations --- .../LockableResourcesRootAction/index.jelly | 67 +++++++------------ .../index.properties | 66 ++++++++++++++++++ 2 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 50a163dd7..ae08fea13 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -13,31 +13,27 @@ + - - - - - - - - -
LabelFree resources
LabelFree resources
${label}0${label}0 ${label}1${label}1 ${label}${it.getFreeResourceAmount(label)}${label}${it.getFreeResourceAmount(label)}
- -

${%header.labels}

- - - - - - - - - - - - - - - - - - - - - - - - - -
${%labels.table.column.labels}${%labels.table.column.free}
${label}0${label}1${label}${it.getFreeResourceAmount(label)}
-
+ +

${%header.labels}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
${%labels.table.column.labels}${%labels.table.column.free}${%labels.table.column.assigned}
+ ${label} + + ${freeCount} + + ${allCount} +
+ +
+
+ +
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties index 27468c3b2..3df1e818b 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -63,4 +66,6 @@ btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties index 8252636cb..93bcf1460 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties @@ -56,4 +56,5 @@ btn.editNote=Pozn\u00e1mka btn.editNote.detail=Upravit pozn\u00e1mku. #table labels labels.table.column.labels=Popisky -labels.table.column.free=Voln\u00e9 zdroje \ No newline at end of file +labels.table.column.free=Voln\u00e9 zdroje +labels.table.column.assigned=P\u0159iraden\u00e9 zdroje \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties index 39c6d0e4c..08684ed88 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties @@ -56,4 +56,5 @@ btn.editNote=Pozn\u00e1mka btn.editNote.detail=Upravi\u0165 pozn\u00e1mku. #table labels labels.table.column.labels=\u0160t\u00edtok -labels.table.column.free=Vo\u013en\u00e9 zdroje \ No newline at end of file +labels.table.column.free=Vo\u013en\u00e9 zdroje +labels.table.column.assigned=Priraden\u00e9 zdroje \ No newline at end of file diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java index 07527be66..0d15c8a5d 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceRootActionSEC1361Test.java @@ -67,6 +67,8 @@ private void checkXssWithResourceName(String resourceName) throws Exception { final AtomicReference lastAlertReceived = new AtomicReference<>(); wc.setAlertHandler((page, s) -> lastAlertReceived.set(s)); + // disable exceptions, otherwise it will not parse jQuery scripts (used ba DataTable plugin) + wc.getOptions().setThrowExceptionOnScriptError(false); HtmlPage htmlPage = wc.goTo("lockable-resources"); assertThat(lastAlertReceived.get(), nullValue()); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java index 44bc22b54..76af0377d 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/TestHelpers.java @@ -77,6 +77,8 @@ public static JSONObject getApiData(JenkinsRule rule) throws IOException { // Currently assumes one resource or only clicks the button for the first resource public static void clickButton(JenkinsRule.WebClient wc, String action) throws Exception { + // disable exceptions, otherwise it will not parse jQuery scripts (used ba DataTable plugin) + wc.getOptions().setThrowExceptionOnScriptError(false); HtmlPage htmlPage = wc.goTo("lockable-resources"); List allButtons = htmlPage.getDocumentElement().getElementsByTagName("button"); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java b/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java new file mode 100644 index 000000000..71ddd7a1c --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java @@ -0,0 +1,586 @@ +package org.jenkins.plugins.lockableresources.actions; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + + +import hudson.model.Item; +import hudson.model.User; +import hudson.security.AccessDeniedException3; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import javax.servlet.ServletException; +import jenkins.model.Jenkins; +import org.jenkins.plugins.lockableresources.LockStepTestBase; +import org.jenkins.plugins.lockableresources.LockableResource; +import org.jenkins.plugins.lockableresources.LockableResourcesManager; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.MockAuthorizationStrategy; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.context.SecurityContextHolder; + + +public class LockableResourcesRootActionTest extends LockStepTestBase { + + @Rule public JenkinsRule j = new JenkinsRule(); + + @Mock + private StaplerRequest req; + + @Mock + private StaplerResponse rsp; + + private AutoCloseable mocks; + + private final String USER = "user"; + private User user; + private final String USER_WITH_CONFIGURE_PERM = "cfg_user"; + private User cfg_user; + private final String USER_WITH_RESERVE_PERM = "reserve_user1"; + private User reserve_user1; + private final String USER_WITH_RESERVE_PERM_2 = "reserve_user2"; + private User reserve_user2; + private final String USER_WITH_STEAL_PERM = "steal_user"; + private User steal_user; + private final String USER_WITH_UNLOCK_PERM = "unlock_user"; + private User unlock_user; + private final String ADMIN = "admin"; + private User admin; + + private LockableResourcesManager LRM = null; + + //--------------------------------------------------------------------------- + @Before + public void setUp() throws Exception { + this.mocks = MockitoAnnotations.openMocks(this); + + this.user = User.getById(this.USER, true); + this.cfg_user = User.getById(this.USER_WITH_CONFIGURE_PERM, true); + this.reserve_user1 = User.getById(this.USER_WITH_RESERVE_PERM, true); + this.reserve_user2 = User.getById(this.USER_WITH_RESERVE_PERM_2, true); + this.steal_user = User.getById(this.USER_WITH_STEAL_PERM, true); + this.unlock_user = User.getById(this.USER_WITH_UNLOCK_PERM, true); + this.admin = User.getById(this.ADMIN, true); + + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + this.j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() + .grant(Jenkins.READ).everywhere().to(this.USER) + .grant(Jenkins.READ, Item.CONFIGURE).everywhere().to(this.USER_WITH_CONFIGURE_PERM) + .grant(Jenkins.READ, Item.CONFIGURE, LockableResourcesRootAction.RESERVE).everywhere().to(this.USER_WITH_RESERVE_PERM) + .grant(Jenkins.READ, Item.CONFIGURE, LockableResourcesRootAction.RESERVE).everywhere().to(this.USER_WITH_RESERVE_PERM_2) + .grant(Jenkins.READ, Item.CONFIGURE, LockableResourcesRootAction.STEAL).everywhere().to(this.USER_WITH_STEAL_PERM) + .grant(Jenkins.READ, Item.CONFIGURE, LockableResourcesRootAction.UNLOCK).everywhere().to(this.USER_WITH_UNLOCK_PERM) + .grant(Jenkins.ADMINISTER).everywhere().to(this.ADMIN) + ); + + this.LRM = LockableResourcesManager.get(); + } + + @After + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + } + + //--------------------------------------------------------------------------- + /** Test action doReassign in web client. + * The action shall do: + * ``` + * Reserves a resource that may be or not be reserved by some person already, giving it away to + * the userName indefinitely (until that person, or some explicit scripted action, decides to + * release the resource). + * ``` + * @throws Exception + */ + @Test + public void testDoReassign() throws Exception { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + LockableResource resource = this.createResource("resource1"); + + // somebody + SecurityContextHolder.getContext().setAuthentication(this.user.impersonate2()); + assertThrows(AccessDeniedException.class, () -> action.doReserve(req, rsp)); + assertFalse("user without permission", resource.isReserved()); + + // switch to suer with reserve permission + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + + assertFalse("is free", resource.isReserved()); + action.doReserve(req, rsp); + assertEquals("reserved by user", this.reserve_user1.getId(), resource.getReservedBy()); + + // try to reassign as other user + // it shall not changes, because the second user has not steal permission + SecurityContextHolder.getContext().setAuthentication(this.reserve_user2.impersonate2()); + assertThrows(AccessDeniedException.class, () -> action.doReassign(req, rsp)); + assertEquals("still reserved by user", this.reserve_user1.getId(), resource.getReservedBy()); + + // switch to user who has reserved the resource and try to reassign + // The user can no do any action here, because he has no STEAL permission + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + assertThrows(AccessDeniedException.class, () -> action.doReassign(req, rsp)); + assertEquals("reserved by user", this.reserve_user1.getId(), resource.getReservedBy()); + + // switch to admin and try to reassign + SecurityContextHolder.getContext().setAuthentication(this.admin.impersonate2()); + action.doReassign(req, rsp); + assertEquals("reserved by admin", this.admin.getId(), resource.getReservedBy()); + + // try to steal reservation + SecurityContextHolder.getContext().setAuthentication(this.steal_user.impersonate2()); + action.doReassign(req, rsp); + assertEquals("reserved by steal user", this.steal_user.getId(), resource.getReservedBy()); + + // do reassign your self, makes no sense, but the application shall not crashed + action.doReassign(req, rsp); + assertEquals("reserved by steal user", this.steal_user.getId(), resource.getReservedBy()); + + // defensive tests + when(req.getParameter("resource")).thenReturn("this-one-does-not-exists"); + action.doReassign(req, rsp); + } + + //--------------------------------------------------------------------------- + @Test + public void testDoReserve() throws Exception { + + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + LockableResource resource = null; + + // nobody (system user) + // system must be permitted to create resource + resource = this.createResource("resource1"); + action.doReserve(req, rsp); + assertTrue("is reserved by system", resource.isReserved()); + + // somebody + SecurityContextHolder.getContext().setAuthentication(this.user.impersonate2()); + resource = this.createResource("resource2"); + assertThrows(AccessDeniedException3.class, () -> action.doReserve(req, rsp)); + assertFalse("user without permission", resource.isReserved()); + + // first user. This shall works + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + action.doReserve(req, rsp); + assertTrue("reserved by first user", resource.isReserved()); + + // second user, shall not work, because it is reserved just now + SecurityContextHolder.getContext().setAuthentication(this.reserve_user2.impersonate2()); + action.doReserve(req, rsp); + assertEquals("still reserved by first user", this.reserve_user1.getId(), resource.getReservedBy()); + + // but create new one and reserve it must works as well + resource = this.createResource("resource3"); + action.doReserve(req, rsp); + assertEquals("reserved by second user", this.reserve_user2.getId(), resource.getReservedBy()); + + // and also admin can not reserve resource, when is reserved just now (need to use reassign action) + SecurityContextHolder.getContext().setAuthentication(this.admin.impersonate2()); + action.doReserve(req, rsp); + assertEquals("still reserved by second user", this.reserve_user2.getId(), resource.getReservedBy()); + + // try to reserve by label name + resource = this.createResource("resource4"); + when(req.getParameter("resource")).thenReturn(resource.getLabels()); + action.doReserve(req, rsp); + // this is not supported at the moment, therefore expected == null + assertEquals("check by label name :" + resource.getLabels(), null, resource.getReservedBy()); + + // invalid params. Just check if it crash here + when(req.getParameter("resource")).thenReturn("this-one-does-not-exists"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("this one does not exists"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn(null); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn(""); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("some-dangerous_characters-like:\n\t$%ÖÜä?=+ľšť"); + action.doReserve(req, rsp); + } + + //--------------------------------------------------------------------------- + @Test + public void testDoReset() throws IOException, ServletException { + + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + LockableResource resource = null; + + // nobody (system user) + // system must be permitted to create resource + resource = this.createResource("resource1"); + action.doReserve(req, rsp); + assertTrue("is reserved by system", resource.isReserved()); + action.doReset(req, rsp); + assertFalse("is reset by system ", resource.isReserved()); + + // somebody + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + action.doReserve(req, rsp); + assertTrue("is reserved by user1 ", resource.isReserved()); + assertThrows(AccessDeniedException3.class, () -> action.doReset(req, rsp)); + assertTrue("still reserved by user1", resource.isReserved()); + + // switch to user with unlock permission + SecurityContextHolder.getContext().setAuthentication(this.unlock_user.impersonate2()); + action.doReset(req, rsp); + assertFalse("unreserved", resource.isReserved()); + + // invalid params. Just check if it crash here + when(req.getParameter("resource")).thenReturn("this-one-does-not-exists"); + action.doReset(req, rsp); + when(req.getParameter("resource")).thenReturn("this one does not exists"); + action.doReset(req, rsp); + when(req.getParameter("resource")).thenReturn(null); + action.doReset(req, rsp); + when(req.getParameter("resource")).thenReturn(""); + action.doReset(req, rsp); + when(req.getParameter("resource")).thenReturn("some-dangerous_characters-like:\n\t$%ÖÜä?=+ľšť"); + action.doReset(req, rsp); + } + + //--------------------------------------------------------------------------- + @Test + public void testDoSaveNote() throws IOException, ServletException { + + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + LockableResource resource = null; + + // nobody (system user) + // system must be permitted to create resource + resource = this.createResource("resource1"); + assertEquals("default note", "", resource.getNote()); + when(req.getParameter("note")).thenReturn("this is my note"); + action.doSaveNote(req, rsp); + assertEquals("default note", "this is my note", resource.getNote()); + + // somebody + SecurityContextHolder.getContext().setAuthentication(this.user.impersonate2()); + assertThrows(AccessDeniedException3.class, () -> action.doSaveNote(req, rsp)); + assertEquals("default note", "this is my note", resource.getNote()); + + // switch to user with reserve permission + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + when(req.getParameter("note")).thenReturn("this is my note from user1"); + action.doSaveNote(req, rsp); + assertEquals("default note", "this is my note from user1", resource.getNote()); + + // switch to other user with reserve permission + SecurityContextHolder.getContext().setAuthentication(this.reserve_user2.impersonate2()); + when(req.getParameter("note")).thenReturn("this is my note from user2"); + action.doSaveNote(req, rsp); + assertEquals("default note", "this is my note from user2", resource.getNote()); + + // invalid params. Just check if it crash here + SecurityContextHolder.getContext().setAuthentication(this.admin.impersonate2()); + when(req.getParameter("note")).thenReturn(""); + action.doSaveNote(req, rsp); + when(req.getParameter("note")).thenReturn(null); + action.doSaveNote(req, rsp); + + when(req.getParameter("resource")).thenReturn("this-one-does-not-exists"); + action.doSaveNote(req, rsp); + when(req.getParameter("resource")).thenReturn("this one does not exists"); + action.doSaveNote(req, rsp); + when(req.getParameter("resource")).thenReturn(null); + action.doSaveNote(req, rsp); + when(req.getParameter("resource")).thenReturn(""); + action.doSaveNote(req, rsp); + when(req.getParameter("resource")).thenReturn("some-dangerous_characters-like:\n\t$%ÖÜä?=+ľšť"); + action.doSaveNote(req, rsp); + + } + + //--------------------------------------------------------------------------- + @Test + public void testDoSteal() throws IOException, ServletException { + + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + LockableResource resource = null; + + // nobody (system user) + // system must be permitted to create resource + resource = this.createResource("resource1"); + // when the resource is not reserved, the doSteal action reserve it for you + action.doSteal(req, rsp); + assertTrue("is reserved by system", resource.isReserved()); + + // somebody + SecurityContextHolder.getContext().setAuthentication(this.reserve_user1.impersonate2()); + action.doReserve(req, rsp); + assertTrue("is reserved by user1 ", resource.isReserved()); + assertThrows(AccessDeniedException3.class, () -> action.doSteal(req, rsp)); + assertTrue("still reserved by user1", resource.isReserved()); + + // switch as admin and reset + SecurityContextHolder.getContext().setAuthentication(this.admin.impersonate2()); + action.doReset(req, rsp); + assertFalse("unreserved", resource.isReserved()); + + // switch to user1 and reserve it + action.doReserve(req, rsp); + assertTrue("is reserved by user1", resource.isReserved()); + + // switch to user with STEAL permission + SecurityContextHolder.getContext().setAuthentication(this.steal_user.impersonate2()); + action.doSteal(req, rsp); + assertEquals("reserved by user", this.steal_user.getId(), resource.getReservedBy()); + + // invalid params. Just check if it crash here + SecurityContextHolder.getContext().setAuthentication(this.admin.impersonate2()); + when(req.getParameter("resource")).thenReturn("this-one-does-not-exists"); + action.doSteal(req, rsp); + when(req.getParameter("resource")).thenReturn("this one does not exists"); + action.doSteal(req, rsp); + when(req.getParameter("resource")).thenReturn(null); + action.doSteal(req, rsp); + when(req.getParameter("resource")).thenReturn(""); + action.doSteal(req, rsp); + when(req.getParameter("resource")).thenReturn("some-dangerous_characters-like:\n\t$%ÖÜä?=+ľšť"); + action.doSteal(req, rsp); + } + + //--------------------------------------------------------------------------- + @Test + public void testDoUnlock() { + + } + + //--------------------------------------------------------------------------- + @Test + public void testDoUnreserve() { + + } + + //--------------------------------------------------------------------------- + @Test + public void testGetAllLabels() throws IOException, ServletException { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + + this.LRM.createResourceWithLabel("resource-A", "resource-label-1"); + this.LRM.createResourceWithLabel("resource-B", "resource-label-1 resource-label-2"); + this.LRM.createResourceWithLabel("resource-C", "resource-label-1 resource-label-2 resource-label-3"); + + + Set expectedLabels = new HashSet<>(); + expectedLabels.add("resource-label-1"); + expectedLabels.add("resource-label-2"); + expectedLabels.add("resource-label-3"); + + Set labels = action.getAllLabels(); + assertEquals("initial check", expectedLabels, labels); + + + LockableResource getter = action.getResource("resource-C"); + assertEquals("initial check", "resource-label-1 resource-label-2 resource-label-3", getter.getLabels()); + assertEquals("initial check", "resource-C", getter.getName()); + } + + //--------------------------------------------------------------------------- + @Test + public void testGetAssignedResourceAmount() throws IOException, ServletException { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + + // initial check, labels are not used + assertEquals("initial check", 0, action.getAssignedResourceAmount("resource-A-label")); + + this.LRM.createResourceWithLabel("resource-A", "resource-label-1"); + this.LRM.createResourceWithLabel("resource-B", "resource-label-1 resource-label-2"); + this.LRM.createResourceWithLabel("resource-C", "resource-label-1 resource-label-2 resource-label-3"); + + assertEquals("initial check", 3, action.getAssignedResourceAmount("resource-label-1")); + assertEquals("initial check", 2, action.getAssignedResourceAmount("resource-label-2")); + assertEquals("initial check", 1, action.getAssignedResourceAmount("resource-label-3")); + + // reserve one resource. Amount of assigned labels should change + when(req.getParameter("resource")).thenReturn("resource-A"); + action.doReserve(req, rsp); + + assertEquals("check after reservation", 3, action.getAssignedResourceAmount("resource-label-1")); + assertEquals("check after reservation", 2, action.getAssignedResourceAmount("resource-label-2")); + assertEquals("check after reservation", 1, action.getAssignedResourceAmount("resource-label-3")); + + // reserve all resources. Amount of assigned labels should change + when(req.getParameter("resource")).thenReturn("resource-B"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-C"); + action.doReserve(req, rsp); + + assertEquals("check after reservation", 3, action.getAssignedResourceAmount("resource-label-1")); + assertEquals("check after reservation", 2, action.getAssignedResourceAmount("resource-label-2")); + assertEquals("check after reservation", 1, action.getAssignedResourceAmount("resource-label-3")); + + // defensive tests + assertEquals("initial check", 0, action.getAssignedResourceAmount("")); + assertEquals("initial check", 0, action.getAssignedResourceAmount(null)); + assertEquals("initial check", 0, action.getAssignedResourceAmount("resource-A-label ")); + } + + //--------------------------------------------------------------------------- + @Test + public void testGetFreeResourceAmount() throws IOException, ServletException { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + + // initial check, labels are not used + assertEquals("initial check", 0, action.getFreeResourceAmount("resource-A-label")); + + this.LRM.createResourceWithLabel("resource-A", "resource-label-1"); + this.LRM.createResourceWithLabel("resource-B", "resource-label-1 resource-label-2"); + this.LRM.createResourceWithLabel("resource-C", "resource-label-1 resource-label-2 resource-label-3"); + + assertEquals("initial check", 3, action.getFreeResourceAmount("resource-label-1")); + assertEquals("initial check", 2, action.getFreeResourceAmount("resource-label-2")); + assertEquals("initial check", 1, action.getFreeResourceAmount("resource-label-3")); + + + when(req.getParameter("resource")).thenReturn("resource-A"); + action.doReserve(req, rsp); + + assertEquals("check after label-1 is reserved", 2, action.getFreeResourceAmount("resource-label-1")); + assertEquals("check after label-1 is reserved", 2, action.getFreeResourceAmount("resource-label-2")); + assertEquals("check after label-1 is reserved", 1, action.getFreeResourceAmount("resource-label-3")); + + when(req.getParameter("resource")).thenReturn("resource-B"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-C"); + action.doReserve(req, rsp); + + assertEquals("check after label-2 is reserved", 0, action.getFreeResourceAmount("resource-label-1")); + assertEquals("check after label-2 is reserved", 0, action.getFreeResourceAmount("resource-label-2")); + assertEquals("check after label-2 is reserved", 0, action.getFreeResourceAmount("resource-label-3")); + + // defensive tests + assertEquals("defensive check", 0, action.getFreeResourceAmount("")); + assertEquals("defensive check", 0, action.getFreeResourceAmount(null)); + assertEquals("defensive check", 0, action.getFreeResourceAmount("resource-A-label ")); + } + + //--------------------------------------------------------------------------- + @Test + public void testGetFreeResourcePercentage() throws IOException, ServletException { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + + // initial check, labels are not used + assertEquals("initial check", 0, action.getFreeResourcePercentage("resource-A-label")); + + this.LRM.createResourceWithLabel("resource-A", "resource-label-1"); + this.LRM.createResourceWithLabel("resource-B", "resource-label-1 resource-label-2"); + this.LRM.createResourceWithLabel("resource-C", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-D", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-E", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-F", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-G", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-H", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-I", "resource-label-1 resource-label-2 resource-label-3"); + this.LRM.createResourceWithLabel("resource-J", "resource-label-1 resource-label-2 resource-label-3"); + + assertEquals("initial check", 100, action.getFreeResourcePercentage("resource-label-1")); + assertEquals("initial check", 100, action.getFreeResourcePercentage("resource-label-2")); + assertEquals("initial check", 100, action.getFreeResourcePercentage("resource-label-3")); + + // reserve one resource. Amount of assigned labels should change + when(req.getParameter("resource")).thenReturn("resource-A"); + action.doReserve(req, rsp); + + assertEquals("check after reservation", 90, action.getFreeResourcePercentage("resource-label-1")); + assertEquals("check after reservation", 100, action.getFreeResourcePercentage("resource-label-2")); + + when(req.getParameter("resource")).thenReturn("resource-B"); + action.doReserve(req, rsp); + assertEquals("check after reservation", 80, action.getFreeResourcePercentage("resource-label-1")); + assertEquals("check after reservation", 88, action.getFreeResourcePercentage("resource-label-2")); + + // reserve all resources. Amount of assigned labels should change + when(req.getParameter("resource")).thenReturn("resource-C"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-D"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-E"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-F"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-G"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-H"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-I"); + action.doReserve(req, rsp); + when(req.getParameter("resource")).thenReturn("resource-J"); + action.doReserve(req, rsp); + + assertEquals("check after all reserved", 0, action.getFreeResourcePercentage("resource-label-1")); + assertEquals("check after all reserved", 0, action.getFreeResourcePercentage("resource-label-2")); + assertEquals("check after all reserved", 0, action.getFreeResourcePercentage("resource-label-3")); + + // defensive tests + assertEquals("defensive check", 0, action.getFreeResourcePercentage("")); + assertEquals("defensive check", 0, action.getFreeResourcePercentage(null)); + assertEquals("defensive check", 0, action.getFreeResourcePercentage("resource-A-label ")); + } + + //--------------------------------------------------------------------------- + @Test + public void testGetIconFileName() { + + } + + //--------------------------------------------------------------------------- + @Test + public void testGetNumberOfAllLabels() throws IOException, ServletException { + when(req.getMethod()).thenReturn("POST"); + LockableResourcesRootAction action = new LockableResourcesRootAction(); + + // initial check, labels are not used + assertEquals("initial check", 0, action.getNumberOfAllLabels()); + + this.LRM.createResourceWithLabel("resource-A", "resource-label-1"); + assertEquals("one resource with one label", 1, action.getNumberOfAllLabels()); + this.LRM.createResourceWithLabel("resource-B", "resource-label-1 resource-label-2"); + assertEquals("two resources with 2 labels", 2, action.getNumberOfAllLabels()); + this.LRM.createResourceWithLabel("resource-C", "resource-label-1 resource-label-2 resource-label-3"); + assertEquals("three resources with three labels", 3, action.getNumberOfAllLabels()); + this.LRM.createResourceWithLabel("resource-D", "resource-label-1 resource-label-2 resource-label-3"); + assertEquals("four resources with three labels", 3, action.getNumberOfAllLabels()); + } + + //--------------------------------------------------------------------------- + @Test + public void testGetUrlName() { + + } + + //--------------------------------------------------------------------------- + @Test + public void testGetUserName() { + + } + + //--------------------------------------------------------------------------- + private LockableResource createResource(String resourceName) { + this.LRM.createResourceWithLabel(resourceName, "label-" + resourceName); + when(req.getParameter("resource")).thenReturn(resourceName); + return LRM.fromName(resourceName); + } +} From cf2eeea17b392ef8c303364d4c5c1c709d9f7250 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Nov 2022 19:00:59 +0000 Subject: [PATCH 0770/1078] Bump bom-2.361.x from 1670.v7f165fc7a_079 to 1678.vc1feb_6a_3c0f1 Bumps [bom-2.361.x](https://github.com/jenkinsci/bom) from 1670.v7f165fc7a_079 to 1678.vc1feb_6a_3c0f1. - [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.361.x 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 0efc5d783..0599c1a34 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ io.jenkins.tools.bom bom-2.361.x - 1670.v7f165fc7a_079 + 1678.vc1feb_6a_3c0f1 import pom From 3d90f05673673e106685de1558b04b8a846f5b2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Nov 2022 19:50:53 +0000 Subject: [PATCH 0771/1078] Bump plugin from 4.49 to 4.50 Bumps [plugin](https://github.com/jenkinsci/plugin-pom) from 4.49 to 4.50. - [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/plugin-4.49...plugin-4.50) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin 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 0599c1a34..41080a4a4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.49 + 4.50 From 0601496eea98837e77725534a181f1c98a0d1c17 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 14 Nov 2022 12:56:33 -0700 Subject: [PATCH 0772/1078] Suppress spotbugs warning for constructor Jenkins constructors frequently call methods that can be overridden --- .../plugins/lockableresources/LockableResourcesManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 20a96bad2..9418f5798 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -57,6 +57,8 @@ public class LockableResourcesManager extends GlobalConfiguration { */ private List queuedContexts = new ArrayList<>(); + @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", + justification = "Common Jenkins pattern to call method that can be overridden") public LockableResourcesManager() { resources = new ArrayList<>(); load(); From 99268e952e2af8921e52f4dc5040d3a3dac17d22 Mon Sep 17 00:00:00 2001 From: Pokorny Martin Date: Tue, 15 Nov 2022 18:49:40 +0100 Subject: [PATCH 0773/1078] [maven-release-plugin] prepare release lockable-resources-2.19 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 41080a4a4..16d588562 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - ${revision}${changelist} + 2.19 hpi Lockable Resources plugin @@ -51,7 +51,7 @@ scm:git:https://github.com/${gitHubRepo}.git scm:git:git@github.com:${gitHubRepo}.git https://github.com/${gitHubRepo} - ${scmTag} + lockable-resources-2.19 From 62426cc20764f60dc2cf689fe94d18f8b31d95f5 Mon Sep 17 00:00:00 2001 From: Pokorny Martin Date: Tue, 15 Nov 2022 19:13:20 +0100 Subject: [PATCH 0774/1078] [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 16d588562..fa40514b7 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - 2.19 + ${revision}${changelist} hpi Lockable Resources plugin @@ -55,7 +55,7 @@ - 2.19 + 2.20 -SNAPSHOT 2.361.1 jenkinsci/${project.artifactId}-plugin From 726298f53f8c90a6a2d99c455ece1907497175fd Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sat, 19 Nov 2022 18:52:41 +0100 Subject: [PATCH 0775/1078] Enable automatic release on merge to master (#400) * Enable automatic release on merge to master --- .github/release-drafter.yml | 3 --- .github/workflows/cd.yaml | 15 +++++++++++++++ .github/workflows/release-drafter.yml | 17 ----------------- .mvn/maven.config | 1 + pom.xml | 7 +++---- 5 files changed, 19 insertions(+), 24 deletions(-) delete mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/cd.yaml delete mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index c6beb6411..000000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1,3 +0,0 @@ -# https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc -_extends: .github -tag-template: lockable-resources-$NEXT_MINOR_VERSION diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml new file mode 100644 index 000000000..0279984d7 --- /dev/null +++ b/.github/workflows/cd.yaml @@ -0,0 +1,15 @@ +# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins + +name: cd +on: + workflow_dispatch: + check_run: + types: + - completed + +jobs: + maven-cd: + uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 + secrets: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml deleted file mode 100644 index 58835450c..000000000 --- a/.github/workflows/release-drafter.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Automates creation of Release Drafts using Release Drafter -# More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc - -on: - push: - branches: - - master - - main - -jobs: - update_release_draft: - runs-on: ubuntu-latest - steps: - # Drafts your next Release notes as Pull Requests are merged into the default branch - - uses: release-drafter/release-drafter@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.mvn/maven.config b/.mvn/maven.config index 2a0299c48..f7daf60d0 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 fa40514b7..b40c5ef05 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.6wind.jenkins lockable-resources - ${revision}${changelist} + ${changelist} hpi Lockable Resources plugin @@ -51,12 +51,11 @@ scm:git:https://github.com/${gitHubRepo}.git scm:git:git@github.com:${gitHubRepo}.git https://github.com/${gitHubRepo} - lockable-resources-2.19 + ${scmTag} - 2.20 - -SNAPSHOT + 999999-SNAPSHOT 2.361.1 jenkinsci/${project.artifactId}-plugin Max From b2d4a465421e225f0c2116427e726f2d8ce2ebb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:09:22 +0000 Subject: [PATCH 0776/1078] Bump plugin from 4.50 to 4.51 Bumps [plugin](https://github.com/jenkinsci/plugin-pom) from 4.50 to 4.51. - [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/plugin-4.50...plugin-4.51) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin 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 b40c5ef05..5307bb016 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.50 + 4.51 From 48721efffaf71023d00635d11e3473b6ae740b93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:09:32 +0000 Subject: [PATCH 0777/1078] Bump bridge-method-annotation from 1.23 to 1.25 Bumps [bridge-method-annotation](https://github.com/jenkinsci/bridge-method-injector) from 1.23 to 1.25. - [Release notes](https://github.com/jenkinsci/bridge-method-injector/releases) - [Commits](https://github.com/jenkinsci/bridge-method-injector/compare/bridge-method-injector-parent-1.23...bridge-method-injector-parent-1.25) --- updated-dependencies: - dependency-name: com.infradna.tool:bridge-method-annotation 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 5307bb016..55e656be3 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ com.infradna.tool bridge-method-annotation - 1.23 + 1.25 provided From 7e4ccc947d5f566d3bfe6ff1e06be68c2d97a308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:52:33 +0000 Subject: [PATCH 0778/1078] Bump bom-2.361.x from 1678.vc1feb_6a_3c0f1 to 1706.vc166d5f429f8 Bumps [bom-2.361.x](https://github.com/jenkinsci/bom) from 1678.vc1feb_6a_3c0f1 to 1706.vc166d5f429f8. - [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.361.x 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 55e656be3..225c5356c 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1678.vc1feb_6a_3c0f1 + 1706.vc166d5f429f8 import pom From d880f7e354e87fe346dab212160abc45375ec316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 21:08:32 +0000 Subject: [PATCH 0779/1078] Bump crowdin/github-action from 1.5.0 to 1.5.1 (#407) Bumps [crowdin/github-action](https://github.com/crowdin/github-action) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/crowdin/github-action/releases) - [Commits](https://github.com/crowdin/github-action/compare/1.5.0...1.5.1) --- updated-dependencies: - dependency-name: crowdin/github-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 9cc4b618f..9e681169b 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 - name: crowdin action - uses: crowdin/github-action@1.5.0 + uses: crowdin/github-action@1.5.1 with: upload_translations: false download_translations: true From c7faf542189ecba5b593741ef4363049d3bcc922 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Sun, 20 Nov 2022 12:14:58 +0000 Subject: [PATCH 0780/1078] Add Gitter badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4eb1b4ad6..80fe8c25c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) [![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) [![Maintenance](https://img.shields.io/maintenance/yes/2022.svg)](https://github.com/jenkinsci/lockable-resources-plugin) -[![Crowdin](https://badges.crowdin.net/e/656dcffac5a09ad0fbdedcb430af1904/localized.svg)](https://jenkins.crowdin.com/lockable-resources-plugin) +[![Crowdin](https://badges.crowdin.net/e/656dcffac5a09ad0fbdedcb430af1904/localized.svg)](https://jenkins.crowdin.com/lockable-resources-plugin) [![Join the chat at https://gitter.im/jenkinsci/lockable-resources](https://badges.gitter.im/jenkinsci/lockable-resources.svg)](https://gitter.im/jenkinsci/lockable-resources?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) This plugin allows defining lockable resources (such as printers, phones, computers, etc.) that can be used by builds. If a build requires a resource From 241b2278bba2312fb2f0fbf4a92f41eeab4f552c Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 20 Nov 2022 18:58:48 +0100 Subject: [PATCH 0781/1078] Format README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 80fe8c25c..26e63d804 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Flockable-resources-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/lockable-resources-plugin/job/master/) [![GitHub license](https://img.shields.io/github/license/jenkinsci/lockable-resources-plugin.svg)](https://github.com/jenkinsci/lockable-resources-plugin/blob/master/LICENSE.txt) [![Maintenance](https://img.shields.io/maintenance/yes/2022.svg)](https://github.com/jenkinsci/lockable-resources-plugin) -[![Crowdin](https://badges.crowdin.net/e/656dcffac5a09ad0fbdedcb430af1904/localized.svg)](https://jenkins.crowdin.com/lockable-resources-plugin) [![Join the chat at https://gitter.im/jenkinsci/lockable-resources](https://badges.gitter.im/jenkinsci/lockable-resources.svg)](https://gitter.im/jenkinsci/lockable-resources?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Crowdin](https://badges.crowdin.net/e/656dcffac5a09ad0fbdedcb430af1904/localized.svg)](https://jenkins.crowdin.com/lockable-resources-plugin) +[![Join the chat at https://gitter.im/jenkinsci/lockable-resources](https://badges.gitter.im/jenkinsci/lockable-resources.svg)](https://gitter.im/jenkinsci/lockable-resources?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) This plugin allows defining lockable resources (such as printers, phones, computers, etc.) that can be used by builds. If a build requires a resource From 9f5dd8bb47c31f2c7420d7556c1f691114077063 Mon Sep 17 00:00:00 2001 From: Jagruti Tiwari Date: Sat, 26 Nov 2022 14:08:57 +0530 Subject: [PATCH 0782/1078] Join Gitter channel to discuss your ideas with the community (#405) * updated readme with gitter channel info --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26e63d804..7a189dd63 100644 --- a/README.md +++ b/README.md @@ -181,8 +181,8 @@ Please report issues and enhancements through the [Jenkins issue tracker in GitH Contributions are welcome, please refer to the separate [CONTRIBUTING](CONTRIBUTING.md) document for details on how to proceed! +Join [Gitter channel](https://gitter.im/jenkinsci/lockable-resources) to discuss your ideas with the community. ## License - All source code is licensed under the MIT license. See [LICENSE](LICENSE.txt) From 71ed6c4dc03844364cbfc2f804b6746bfdfa8ad6 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 26 Nov 2022 18:54:58 +0100 Subject: [PATCH 0783/1078] New Crowdin updates (#396) * New translations index.properties (Romanian) * New translations index.properties (Vietnamese) * New translations index.properties (Portuguese, Brazilian) * New translations index.properties (Chinese Traditional) * New translations index.properties (English) * New translations index.properties (French) * New translations index.properties (Hungarian) * New translations index.properties (Spanish) * New translations index.properties (Afrikaans) * New translations index.properties (Arabic) * New translations index.properties (Catalan) * New translations index.properties (Czech) * New translations index.properties (Danish) * New translations index.properties (German) * New translations index.properties (Greek) * New translations index.properties (Finnish) * New translations index.properties (Hebrew) * New translations index.properties (Italian) * New translations index.properties (Ukrainian) * New translations index.properties (Japanese) * New translations index.properties (Korean) * New translations index.properties (Dutch) * New translations index.properties (Norwegian) * New translations index.properties (Polish) * New translations index.properties (Russian) * New translations index.properties (Serbian (Cyrillic)) * New translations index.properties (Swedish) * New translations index.properties (Turkish) * New translations index.properties (Slovak) * New translations index.properties (French) * New translations index.properties (Czech) * New translations index.properties (German) * New translations index.properties (Slovak) * New translations index.properties (Slovak) * New translations config.properties (Czech) * New translations config.properties (Czech) * New translations config.properties (Czech) * New translations index.properties (Romanian) * New translations index.properties (Vietnamese) * New translations index.properties (Portuguese, Brazilian) * New translations index.properties (Chinese Traditional) * New translations index.properties (English) * New translations index.properties (Hungarian) * New translations index.properties (Spanish) * New translations index.properties (Afrikaans) * New translations index.properties (Arabic) * New translations index.properties (Catalan) * New translations index.properties (Czech) * New translations index.properties (Danish) * New translations index.properties (Greek) * New translations index.properties (Finnish) * New translations index.properties (Hebrew) * New translations index.properties (Italian) * New translations index.properties (Ukrainian) * New translations index.properties (Japanese) * New translations index.properties (Korean) * New translations index.properties (Dutch) * New translations index.properties (Norwegian) * New translations index.properties (Polish) * New translations index.properties (Russian) * New translations index.properties (Serbian (Cyrillic)) * New translations index.properties (Swedish) * New translations index.properties (Turkish) * New translations config.properties (Slovak) * New translations Messages.properties (French) * New translations Messages.properties (Czech) * New translations Messages.properties (Slovak) Co-authored-by: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> --- .../LockStep/config_cs.properties | 4 ++-- .../config_cs.properties | 2 +- .../lockableresources/Messages_cs.properties | 4 ++-- .../lockableresources/Messages_fr.properties | 2 +- .../lockableresources/Messages_sk.properties | 4 ++-- .../config_cs.properties | 2 +- .../config_sk.properties | 2 +- .../index_af.properties | 9 +++++++-- .../index_ar.properties | 9 +++++++-- .../index_ca.properties | 9 +++++++-- .../index_cs.properties | 16 ++++++++++------ .../index_da.properties | 9 +++++++-- .../index_de.properties | 9 +++++++-- .../index_el.properties | 9 +++++++-- .../index_en.properties | 9 +++++++-- .../index_es.properties | 9 +++++++-- .../index_fi.properties | 9 +++++++-- .../index_fr.properties | 7 ++++++- .../index_he.properties | 9 +++++++-- .../index_hu.properties | 9 +++++++-- .../index_it.properties | 9 +++++++-- .../index_ja.properties | 9 +++++++-- .../index_ko.properties | 9 +++++++-- .../index_nl.properties | 9 +++++++-- .../index_no.properties | 9 +++++++-- .../index_pl.properties | 9 +++++++-- .../index_pt.properties | 9 +++++++-- .../index_ro.properties | 9 +++++++-- .../index_ru.properties | 9 +++++++-- .../index_sk.properties | 18 +++++++++++------- .../index_sr.properties | 9 +++++++-- .../index_sv.properties | 9 +++++++-- .../index_tr.properties | 9 +++++++-- .../index_uk.properties | 9 +++++++-- .../index_vi.properties | 9 +++++++-- .../index_zh.properties | 9 +++++++-- 36 files changed, 219 insertions(+), 76 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_cs.properties index 35969a134..132ffb6b7 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_cs.properties @@ -22,8 +22,8 @@ entry.resource.title=Zdroj entry.label.title=Popisek -entry.quantity.title=Po\u010det -entry.variable.title=Prom\u011bnn\u00e1 v\u00fdsledk\u016f +entry.quantity.title=Mno\u017estv\u00ed +entry.variable.title=Prom\u011bnn\u00e1 s v\u00fdsledkemi entry.inversePrecedence.checkbox.title=Obr\u00e1cen\u00e9 po\u0159ad\u00ed entry.inversePrecedence.skipIfLocked.title=P\u0159esko\u010dit frontu entry.extra.title=Dodate\u010dn\u00e9 zdroje diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_cs.properties index 5eb469a3f..9a13642fe 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_cs.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -section.title=Spr\u00e1vca uzamykateln\u00fdch zdroj\u00fa +section.title=Spr\u00e1vce uzamykateln\u00fdch zdroj\u00fa entry.title=Uzamykateln\u00e9 zdroje field.header=Zdroj field.add=P\u0159idat uzamykateln\u00fd zdroj \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_cs.properties index e8a958fcc..e7955a0bb 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_cs.properties @@ -9,11 +9,11 @@ LockableResourcesRootAction.PermissionGroup=Uzamykateln\u00e9 zdroje LockableResourcesRootAction.UnlockPermission=Odemknout -LockableResourcesRootAction.UnlockPermission.Description=Toto opr\u00e1vn\u011bn\u00ed ud\u011bluje mo\u017enost ru\u010dn\u011b odemknout zdroje, kter\u00e9 byly uzam\u010deny staven\u00edmi. +LockableResourcesRootAction.UnlockPermission.Description=Toto opr\u00e1vn\u011bn\u00ed ud\u011bluje mo\u017enost ru\u010dn\u011b odemknout zdroje, kter\u00e9 byly uzam\u010deny sestaven\u00edmi. LockableResourcesRootAction.ReservePermission=Rezervovat LockableResourcesRootAction.ReservePermission.Description=Toto opr\u00e1vn\u011bn\u00ed poskytuje mo\u017enost ru\u010dn\u011b rezervovat uzamykateln\u00e9 zdroje mimo sestaven\u00ed. LockableResourcesRootAction.StealPermission=Ukradnout -LockableResourcesRootAction.StealPermission.Description=Toto opr\u00e1vn\u011bn\u00ed ud\u011bluje manu\u00e1ln\u011b "kr\u00e1de\u017e" suroviny, kter\u00e9 byly uzam\u010deny sestaven\u00edm nebo "p\u0159e\u0159adit" polo\u017eky rezervovan\u00e9 u\u017eivateli. +LockableResourcesRootAction.StealPermission.Description=Toto opr\u00e1vn\u011bn\u00ed ud\u011bluje mo\u017enost manu\u00e1ln\u011b "ukradnout" zdroje, kter\u00e9 byly uzam\u010deny sestaven\u00edm nebo "p\u0159e\u0159adit" polo\u017eky rezervovan\u00e9 u\u017eivateli. LockableResourcesRootAction.ViewPermission=Zobrazit LockableResourcesRootAction.ViewPermission.Description=Toto opr\u00e1vn\u011bn\u00ed ud\u011bluje mo\u017enost zobrazit uzamykateln\u00e9 zdroje. diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties index bb976e2b7..eb5f5fd01 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fr.properties @@ -13,7 +13,7 @@ LockableResourcesRootAction.UnlockPermission.Description=Cette permission accord LockableResourcesRootAction.ReservePermission=R\u00e9server LockableResourcesRootAction.ReservePermission.Description=Cette permission accorde la possibilit\u00e9 de r\u00e9server manuellement les ressources verrouillables \u00e0 l'ext\u00e9rieur d'un build. LockableResourcesRootAction.StealPermission=Voler -LockableResourcesRootAction.StealPermission.Description=Cette permission accorde la possibilit\u00e9 de "voler" manuellement les ressources qui ont \u00e9t\u00e9 verrouill\u00e9es par les builds ou de "r\u00e9assigner" celles r\u00e9serv\u00e9es par les utilisateurs. +LockableResourcesRootAction.StealPermission.Description=Cette permission permet de "voler" manuellement les ressources qui ont \u00e9t\u00e9 verrouill\u00e9es par les builds ou de "r\u00e9assigner" celles r\u00e9serv\u00e9es par les utilisateurs. LockableResourcesRootAction.ViewPermission=Voir LockableResourcesRootAction.ViewPermission.Description=Cette permission accorde la possibilit\u00e9 de voir les ressources verrouillables. diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sk.properties index 57f72dce6..8f2cff42c 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sk.properties @@ -14,6 +14,6 @@ LockableResourcesRootAction.ReservePermission=Rezervova\u0165 LockableResourcesRootAction.ReservePermission.Description=Toto opr\u00e1vnenie poskytuje mo\u017enos\u0165 ru\u010dne rezervova\u0165 uzamykate\u013en\u00e9 zdroje mimo zostavenia. LockableResourcesRootAction.StealPermission=Ukradn\u00fa\u0165 LockableResourcesRootAction.StealPermission.Description=Toto opr\u00e1vnenie umo\u017e\u0148uje manu\u00e1lne "ukradn\u00fa\u0165" zdroj, ktor\u00fd bol uzamknut\u00fd zostaven\u00edm alebo "preradi\u0165" zdroje rezervovan\u00e9 u\u017e\u00edvate\u013eom. -LockableResourcesRootAction.ViewPermission=Zobrazenie -LockableResourcesRootAction.ViewPermission.Description=Toto opr\u00e1vnenie ude\u013euje mo\u017enos\u0165 zobrazi\u0165 uzamykate\u013en\u00e9 zdroje. +LockableResourcesRootAction.ViewPermission=Zobrazi\u0165 +LockableResourcesRootAction.ViewPermission.Description=Toto opr\u00e1vnenie ude\u013euje mo\u017enos\u0165 zobrazi\u0165 zamykate\u013en\u00e9 zdroje. diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_cs.properties index 726df9b9a..2d2fec0b0 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_cs.properties @@ -23,6 +23,6 @@ optionalBlock.title=Toto sestaven\u00ed vy\u017eaduje uzamykateln\u00e9 zdroje entry.resourceNames.title=Zdroje entry.labelName.title=Popisek -optionalProperty.resourceMatchScript.title=Groovy Expression +optionalProperty.resourceMatchScript.title=Groovy k\u00f3d entry.resourceNamesVar.title=N\u00e1zev prom\u011bnn\u00e9 pro rezervovan\u00e9 zdroje entry.resourceNumber.title=Po\u010det zdroj\u016f na vy\u017e\u00e1d\u00e1n\u00ed \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sk.properties index 50c5e0148..1b82c8fd0 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sk.properties @@ -23,6 +23,6 @@ optionalBlock.title=Toto zostavenie vy\u017eaduje uzamykate\u013en\u00e9 zdroje entry.resourceNames.title=Zdroje entry.labelName.title=\u0160t\u00edtok -optionalProperty.resourceMatchScript.title=Groovy Expression +optionalProperty.resourceMatchScript.title=Groovy k\u00f3d entry.resourceNamesVar.title=N\u00e1zov pramennej obsahuj\u00facej rezervovan\u00e9 zdroje entry.resourceNumber.title=Po\u010det zdrojov na vy\u017eiadanie \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_af.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_af.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_af.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ar.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ar.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ar.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ca.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ca.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ca.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties index 93bcf1460..7d3a06559 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_cs.properties @@ -23,6 +23,9 @@ #headers header.resources=Uzamykateln\u00e9 zdroje header.labels=Popisky +#warnig resources not configured +resources.not_configured=V tuto chv\u00edli nejsou nakonfigurov\u00e1ny \u017e\u00e1dn\u00e9 zdroje. +resources.configure.here=M\u016f\u017eete jej nastavit zde. #table resources resources.table.column.resource=Zdroj resources.table.column.status=Stav @@ -31,8 +34,8 @@ resources.table.column.ephemeral=Pominuteln\u00ed resources.table.column.action=Akce #status resource.status.free=VOLN\u00dd -resource.status.locked=UZAMKNUT\u00dd {1} -resource.status.reservedBy=VYHRAZENO {0} +resource.status.locked=ZAM\u010cEN\u00cd {1} +resource.status.reservedBy=REZERVOV\u00c1NO u\u017eivatelem {0} resource.status.reservedBy.tooltip=Rezervov\u00e1no u\u017eivatelem {0} p\u0159ed {1} resource.status.queuedBy=VE FRON\u0164E sestaven\u00edm {0} {1} resource.status.queuedBy.tooltip=Ve front\u011b {0} p\u0159ed {1} @@ -43,8 +46,8 @@ btn.copy.detail=Zkop\u00edrovat n\u00e1zev zdroje do schr\u00e1nky btn.unlock=Odemknout btn.unlock.detail=Odemkne zdroj, kter\u00fd ji\u017e m\u016f\u017ee b\u00fdt nebo nemus\u00ed b\u00fdt uzam\u010den n\u011bjak\u00fdm sestaven\u00edm (nebo rezervov\u00e1n n\u011bkter\u00fdm u\u017eivatelem). btn.steal=Ukradnout z\u00e1mek -btn.steal.detail=Rezervuje zdroj, kter\u00fd m\u016f\u017ee b\u00fdt nebo nemus\u00ed b\u00fdt uzam\u010den n\u011bjak\u00fdm sestaven\u00edm (nebo rezervov\u00e1n n\u011bkter\u00fdm u\u017eivatelem).
P\u0159iraden\u00edm ku aktu\u00e1ln\u011b p\u0159ihl\u00e1\u0161en\u00e9ho u\u017eivatele na neur\u010dito (dokud se tato osoba nebo n\u011bjak\u00e1 explicitn\u00ed skriptovan\u00e1 akce pozd\u011bji rozhodne uvolnit zdroje). -btn.reset=Reset +btn.steal.detail=Rezervuje zdroj, kter\u00fd m\u016f\u017ee b\u00fdt nebo nemus\u00ed b\u00fdt uzam\u010den n\u011bjak\u00fdm sestaven\u00edm (nebo rezervov\u00e1n n\u011bkter\u00fdm u\u017eivatelem).
P\u0159iraden\u00edm ku aktu\u00e1ln\u011b p\u0159ihl\u00e1\u0161en\u00e9ho u\u017eivatele na neur\u010dito (dokud se tato osoba nebo n\u011bjak\u00e1 explicitn\u00ed skriptovac\u00ed akce pozd\u011bji rozhodne uvolnit zdroje). +btn.reset=Resetovat btn.reset.detail=Obnov\u00ed zdroj, kter\u00fd m\u016f\u017ee b\u00fdt rezervov\u00e1n, uzam\u010den nebo ve front\u011b. btn.reserve=Rezervovat btn.reserve.detail=Rezervuje dostupn\u00fd zdroj pro aktu\u00e1ln\u011b p\u0159ihl\u00e1\u0161en\u00e9ho u\u017eivatele na neur\u010dito (dokud se tato osoba nebo n\u011bjak\u00e1 explicitn\u00ed skriptovan\u00e1 akce nerozhodne uvolnit zdroje). @@ -56,5 +59,6 @@ btn.editNote=Pozn\u00e1mka btn.editNote.detail=Upravit pozn\u00e1mku. #table labels labels.table.column.labels=Popisky -labels.table.column.free=Voln\u00e9 zdroje -labels.table.column.assigned=P\u0159iraden\u00e9 zdroje \ No newline at end of file +labels.table.column.free=Voln\u00e9 +labels.table.column.assigned=P\u0159i\u0159azen\u00e9 zdroje +labels.free.tooltip={0} % voln\u00fdch \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_da.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_da.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_da.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_de.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_de.properties index 62d12c15a..ee1d2cb4b 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_de.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_de.properties @@ -23,6 +23,9 @@ #headers header.resources=Sperrbare Ressourcen header.labels=Labels +#warnig resources not configured +resources.not_configured=Derzeit sind keine Ressourcen konfiguriert. +resources.configure.here=Sie k\u00f6nnen es hier konfigurieren. #table resources resources.table.column.resource=Ressource resources.table.column.status=Status @@ -31,7 +34,7 @@ resources.table.column.ephemeral=Ephemisch resources.table.column.action=Aktion #status resource.status.free=FREI -resource.status.locked=GESP\u00c4RT durch {1} +resource.status.locked=GESPERRT durch {1} resource.status.reservedBy=RESERVIERT von {0} resource.status.reservedBy.tooltip=Reserviert von {0} vor {1} resource.status.queuedBy=IN WARTESCHLANGE von {0} {1} @@ -56,4 +59,6 @@ btn.editNote=Notiz btn.editNote.detail=Ressourcennotiz. #table labels labels.table.column.labels=Labels -labels.table.column.free=Freie Ressourcen \ No newline at end of file +labels.table.column.free=Frei +labels.table.column.assigned=Zugewiesene Ressourcen +labels.free.tooltip={0} % frei \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_el.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_el.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_el.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_en.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_en.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_en.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_es.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_es.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_es.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fi.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fi.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fi.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fr.properties index 3eb8c6c7c..46d6db12c 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fr.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fr.properties @@ -23,6 +23,9 @@ #headers header.resources=Ressources verrouillables header.labels=Libell\u00e9s +#warnig resources not configured +resources.not_configured=Il n'y a aucune ressource configur\u00e9e pour le moment. +resources.configure.here=Vous pouvez le configurer ici. #table resources resources.table.column.resource=Ressource resources.table.column.status=Statut @@ -56,4 +59,6 @@ btn.editNote=Note btn.editNote.detail=Modifier la note de la ressource. #table labels labels.table.column.labels=Libell\u00e9s -labels.table.column.free=Ressources disponibles \ No newline at end of file +labels.table.column.free=Libre +labels.table.column.assigned=Ressources affect\u00e9es +labels.free.tooltip={0} % libre \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_he.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_he.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_he.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_hu.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_hu.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_hu.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_it.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_it.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_it.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ja.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ja.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ja.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ko.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ko.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ko.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_nl.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_nl.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_nl.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_no.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_no.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_no.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pl.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pl.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pl.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pt.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pt.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pt.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ro.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ro.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ro.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ru.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ru.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ru.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties index 08684ed88..091dda8a5 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sk.properties @@ -22,11 +22,14 @@ #headers header.resources=Uzamykate\u013en\u00e9 zdroje -header.labels=Popisky +header.labels=\u0160t\u00edtky +#warnig resources not configured +resources.not_configured=Moment\u00e1lne nie s\u00fa nakonfigurovan\u00e9 \u017eiadne zdroje. +resources.configure.here=M\u00f4\u017eete ich nakonfigurova\u0165 tu. #table resources resources.table.column.resource=Zdroj resources.table.column.status=Stav -resources.table.column.labels=Popisky +resources.table.column.labels=\u0160t\u00edtky resources.table.column.ephemeral=Pominute\u013en\u00fd resources.table.column.action=Akcia #status @@ -44,17 +47,18 @@ btn.unlock=Odomkn\u00fa\u0165 btn.unlock.detail=Odomkne zdroj, ktor\u00fd u\u017e m\u00f4\u017ee by\u0165 alebo nemus\u00ed by\u0165 uzamknut\u00fd nejak\u00fdm zostaven\u00edm (alebo rezervovan\u00fd nejak\u00fdm u\u017e\u00edvate\u013eom). btn.steal=Ukradn\u00fa\u0165 z\u00e1mok btn.steal.detail=Rezervuje zdroj, ktor\u00fd m\u00f4\u017ee by\u0165 alebo nemus\u00ed by\u0165 uzamknut\u00fd nejak\u00fdm zostaven\u00edm (alebo rezervovan\u00fd niektor\u00fdm u\u017e\u00edvate\u013eom).
Prirad\u00ed aktu\u00e1lne prihl\u00e1sen\u00e9ho u\u017e\u00edvate\u013ea na neur\u010dito (pokia\u013e ss t\u00e1to osoba alebo nejak\u00e1 explicitn\u00e1 skriptov\u00e1 akcia nesk\u00f4r rozhodne uvolni\u0165 zdroje). -btn.reset=Resetova\u0165 -btn.reset.detail=Resetuje zdroj, ktor\u00fd m\u00f4\u017ee by\u0165 rezervovan\u00fd, uzamknut\u00fd alebo v rade. +btn.reset=Obnovi\u0165 +btn.reset.detail=Obnov\u00ed zdroj, ktor\u00fd m\u00f4\u017ee by\u0165 rezervovan\u00fd, uzamknut\u00fd alebo v rade. btn.reserve=Rezervova\u0165 btn.reserve.detail=Rezervuje dostupn\u00fd zdroj pre aktu\u00e1lne prihl\u00e1sen\u00e9ho u\u017e\u00edvate\u013ea na neur\u010dito (pokia\u013e se t\u00e1to osoba alebo nejak\u00e1 explicitn\u00e1 skriptovacia akcia nerozhodne uvolni\u0165 zdroj). -btn.unReserve=Zru\u0161i\u0165 rezervu +btn.unReserve=Zru\u0161i\u0165 rezerv\u00e1ciu btn.unReserve.detail=Zru\u0161\u00ed rezerv\u00e1ciu, ktor\u00e1 m\u00f4\u017ee by\u0165 u\u017e rezervovan\u00e1 nejakou osobou.
U\u017e\u00edvate\u013e m\u00f4\u017ee zru\u0161i\u0165 iba vlastn\u00fa rezerv\u00e1ciu. Administr\u00e1tor m\u00f4\u017ee zru\u0161i\u0165 ak\u00fako\u013evek rezerv\u00e1ciu. -btn.reassign=Preradi\u0165 +btn.reassign=Prideli\u0165 btn.reassign.detail=Rezervuje zdroj, ktor\u00fd m\u00f4\u017ee by\u0165 alebo nemus\u00ed by\u0165 rezervovan\u00fd niektor\u00fdm u\u017e\u00edvate\u013eom.
Prirad\u00ed aktu\u00e1lne prihl\u00e1sen\u00e9ho u\u017e\u00edvate\u013ea na neur\u010dito (pokia\u013e sa t\u00e1to osoba alebo nejak\u00e1 explicitn\u00e1 skriptovacia akcia nesk\u00f4r rozhodne uvolni\u0165 zdroje)
T\u00fato akciu m\u00f4\u017ee vykona\u0165 iba administr\u00e1tor. btn.editNote=Pozn\u00e1mka btn.editNote.detail=Upravi\u0165 pozn\u00e1mku. #table labels labels.table.column.labels=\u0160t\u00edtok labels.table.column.free=Vo\u013en\u00e9 zdroje -labels.table.column.assigned=Priraden\u00e9 zdroje \ No newline at end of file +labels.table.column.assigned=Priraden\u00e9 zdroje +labels.free.tooltip={0} % vo\u013en\u00fdch \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sr.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sr.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sr.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sv.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sv.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sv.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_tr.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_tr.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_tr.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_uk.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_uk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_uk.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_vi.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_vi.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_vi.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_zh.properties index 1fdf6d428..aa2ecba94 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_zh.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_zh.properties @@ -23,6 +23,9 @@ #headers header.resources=Lockable Resources header.labels=Labels +#warnig resources not configured +resources.not_configured=There are no resources configured at the moment. +resources.configure.here=You can configure it here. #table resources resources.table.column.resource=Resource resources.table.column.status=Status @@ -51,9 +54,11 @@ btn.reserve.detail=Reserves an available resource for currently logged user inde btn.unReserve=Unreserve btn.unReserve.detail=Un-reserves a resource that may be reserved by some person already.
The user can unreserve only own resource. Administrator can unreserve any resource. btn.reassign=Reassign -btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource). +btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
Giving it away to currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
This action can be done only by administrator. btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels labels.table.column.labels=Labels -labels.table.column.free=Free resources \ No newline at end of file +labels.table.column.free=Free +labels.table.column.assigned=Assigned resources +labels.free.tooltip={0} % free \ No newline at end of file From 7a87199c16e2e4a9e293d1aaa0c959698feadcd8 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 27 Nov 2022 20:42:32 +0100 Subject: [PATCH 0784/1078] Add more examples (#403) Add more examples --- PULL_REQUEST_TEMPLATE.md | 32 ++- README.md | 12 +- src/doc/examples/lock-nodes.md | 185 ++++++++++++++++++ ...ng-multiple-stages-in-declarative-pipeline | 33 ++++ src/doc/examples/readme.md | 9 + .../index.properties | 3 +- 6 files changed, 253 insertions(+), 21 deletions(-) create mode 100644 src/doc/examples/lock-nodes.md create mode 100644 src/doc/examples/locking-multiple-stages-in-declarative-pipeline create mode 100644 src/doc/examples/readme.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 618d79431..db93e0b93 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -28,16 +28,6 @@ For frontend changes, include screenshots of the relevant page(s) before and aft For refactoring and code cleanup changes, exercise the code before and after the change and verify the behavior remains the same. --> -### Proposed changelog entries - -- Entry 1: Issue, human-readable text -- […] - - - ### Proposed upgrade guidelines N/A @@ -46,13 +36,16 @@ N/A - [ ] English -- [ ] Franc +- [ ] German +- [ ] French - [ ] Slovak - [ ] Czech - [ ] ... @@ -61,15 +54,20 @@ English text's are mandatory for new entries. - [ ] The Jira / Github issue, if it exists, is well-described. - [ ] The changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developers, depending on the change) and are in the imperative mood (see [examples](https://github.com/jenkins-infra/jenkins.io/blob/master/content/_data/changelogs/weekly.yml)). + - The changelog generator for plugins uses the **pull request title as the changelog entry**. - Fill in the **Proposed upgrade guidelines** section only if there are breaking changes or changes that may require extra steps from users during the upgrade. - [ ] There is automated testing or an explanation that explains why this change has no tests. -- [ ] New public classes, fields, and methods are annotated with `@Restricted` or have `@since TODO` Javadocs, as appropriate. - [ ] New public functions for internal use only are annotated with `@NoExternalUse`. In case it is used by non java code the `Used by {@code .jelly}` Javadocs are annotated. + - [ ] New or substantially changed JavaScript is not defined inline and does not call `eval` to ease the future introduction of Content Security Policy (CSP) directives (see [documentation](https://www.jenkins.io/doc/developer/security/csp/)). - [ ] For dependency updates, there are links to external changelogs and, if possible, full differentials. - [ ] For new APIs and extension points, there is a link to at least one consumer. - [ ] Any localizations are transferred to *.properties files. +- [ ] Changes in the interface are documented also as [examples](src/doc/examples/readme.md). ### Maintainer checklist @@ -77,7 +75,7 @@ Before the changes are marked as `ready-for-merge`: - [ ] There is at least one (1) approval for the pull request and no outstanding requests for change. - [ ] Conversations in the pull request are over, or it is explicit that a reviewer is not blocking the change. -- [ ] Changelog entries in the pull request title and/or **Proposed changelog entries** are accurate, human-readable, and in the imperative mood. -- [ ] Proper changelog labels are set so that the changelog can be generated automatically. +- [ ] Changelog entries in the **pull request title** and/or **Proposed changelog entries** are accurate, human-readable, and in the imperative mood. +- [ ] Proper changelog labels are set so that the changelog can be generated automatically. See also [release-drafter-labels](https://github.com/jenkinsci/.github/blob/ce466227c534c42820a597cb8e9cac2f2334920a/.github/release-drafter.yml#L9-L50). - [ ] If the change needs additional upgrade steps from users, the `upgrade-guide-needed` label is set and there is a **Proposed upgrade guidelines** section in the pull request title (see [example](https://github.com/jenkinsci/jenkins/pull/4387)). - [ ] java code changes are tested by automated test. diff --git a/README.md b/README.md index 7a189dd63..734946b2c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,13 @@ Each lockable resource has the following properties: the resource will be unavailable for jobs. i.e. `All printers are currently not available due to maintenance.` This option is still possible, but we recommend to use the page `/lockable-resources/` +A resource is always the one thing that is locked (or free or reserved). +It exists once and has an unique name (if we take the hardware example, this may be `office_printer_14`). +Every resource can have multiple labels (the printer could be labeled `dot-matrix-printer`, `in-office-printer`, `a4-printer`, etc.). +All resources with the same label form a "pool", so if you try to lock an `a4-printer`, one of the resources with the label `a4-printer` will be locked when it is available. +If all resources with the label `a4-printer` are in use, your job waits until one is available. +This is similar to nodes and node labels. + ### Using a resource in a freestyle job When configuring the job, select **This build requires lockable resources**. @@ -129,6 +136,8 @@ lock( echo 'Finish' ``` +More examples are [here](src/doc/examples/readme.md). + ## Configuration as Code This plugin can be configured via @@ -140,11 +149,10 @@ This plugin can be configured via unclassified: lockableResourcesManager: declaredResources: - - name: "S7_1200_1 " + - name: "S7_1200_1" description: "S7 PLC model 1200" labels: "plc:S7 model:1200" reservedBy: "Reserved due maintenance window" - declaredResources: - name: "S7_1200_2" labels: "plc:S7 model:1200" ``` diff --git a/src/doc/examples/lock-nodes.md b/src/doc/examples/lock-nodes.md new file mode 100644 index 000000000..44f97a778 --- /dev/null +++ b/src/doc/examples/lock-nodes.md @@ -0,0 +1,185 @@ +# Examples + +## Node dependent resources + +Locking a resource that depends on a specific node can be very helpful in many cases. +That means a job must pick a target node that has the requested resource available. + +```groovy +// allocate node +node('some-build-node') { + // Lock resource named *whatever-resource-some-build-node* + lock("whatever-resource-${env.NODE_NAME}") { + echo "Running on node ${env.NODE_NAME} with locked resource ${env.LOCKED_RESOURCE}" + } +} +``` + +But much more useful is lock node first. + +```groovy +// Lock resource named *some-build-node* +lock('some-build-node') { + // allocate node + node(env.LOCKED_RESOURCE) { + + echo "I am no node ${env.NODE_NAME} and locked resource ${env.LOCKED_RESOURCE}" + } +} +``` + +Let explain in more complex use case. + +*Request:* +Our job tests server-client integration. That means we need 2 nodes (1 server and 1 client). +On every node must be test sources up-to-date. +Tests are running only on client side. + +*Solution:* +Create 2 nodes: + +- node-server +- node-client + +and execute it parallel like this: + +```groovy +Map stages = [:]; +stages['server'] = { + node('node-server') { + prepareTests() + startServer() + } +} +stages['client'] = { + node('node-client') { + prepareTests() + startClientTest() + } +} +// execute all prepare stages synchronous +parallel stages + +// Prepare tests on node +void prepareTests() { + checkout([$class: 'GitSCM', + branches: [[name: 'master']] + ]) +} +// Start server +void startServer() { + echo 'Server will be started in few seconds' + sh 'mvn clean hpi:run' + echo 'Server is done' +} +// Start client +void startClientTest() { + sleep 20 + sh 'mvn clean verify' +} +``` + +It looks pretty fine and easy, but !!!. + +Executing all steps parallel might leads to timing issues, because checkout on server-node might takes much longer then on client-node. This is serious issue because the client starts before the server and can not connect to server. + +The solution is to synchronized parallel stages like this. + +```groovy +Map prepareStages = [:]; +prepareStages['server'] = { + node('node-server') { + prepareTests() + } +} +prepareStages['client'] = { + node('node-client') { + startServer() + } +} +// execute all prepare stages synchronous +parallel prepareStages + +Map testStages = [:] +testStages['server'] = { + node('node-server') { + prepareTests(); + } +} +testStages['client'] = { + node('node-client') { + sleep 20 + startClientTest(); + } +} + +// execute all test stages at the same time +testStages.failFast = true +parallel testStages + +... +``` + +Ok we solve the timing issue, but what is wrong here? + +When the step *parallel prepareStages* is done then are on both nodes executors free. At this moment +it might happen, that some other job allocate one of the nodes. This will leads to more side effects, like: + +- no body can grant, that currently checked out workspace will be untouched +- no body can grant how long will be the node allocated +- ... and many others + +Instead, we lock both nodes with a single call to `lock`. + +Create two resources: +name | Labels | +---------------|--------| +nodes-server-1 | server-node | +nodes-client-1 | client-node | + + +```groovy +lock(variable: 'locked_resources', + extra: [ + [label: 'server-node', quantity: 1], + [label: 'client-node', quantity: 1] + ) { + final String serverNodeName = env.LOCKED_RESOURCE0; + final String clientNodeName = env.LOCKED_RESOURCE1; + Map prepareStages = [:]; + prepareStages['server'] = { + node(serverNodeName) { + prepareTests() + } + } + prepareStages['client'] = { + node(clientNodeName) { + startServer() + } + } + // execute all prepare stages synchronous + parallel prepareStages + + Map testStages = [:] + testStages['server'] = { + node(serverNodeName) { + prepareTests(); + } + } + testStages['client'] = { + node(clientNodeName) { + sleep 20 + startClientTest(); + } + } + + // execute all test stages at the same time + testStages.failFast = true + parallel testStages + +} + +... +``` + +Keep in mind, that `lock()` only helps when locks are consistently requested for resources. diff --git a/src/doc/examples/locking-multiple-stages-in-declarative-pipeline b/src/doc/examples/locking-multiple-stages-in-declarative-pipeline new file mode 100644 index 000000000..e030fe85a --- /dev/null +++ b/src/doc/examples/locking-multiple-stages-in-declarative-pipeline @@ -0,0 +1,33 @@ +# Locking multiple stages in declarative pipeline + +You can lock the entire job in the options block of the pipeline: + +```groovy +pipeline { +options { + lock resource: 'lockable resource' + } + + + agent any + + stages { + stage('Build') { + steps { + sh 'make' + } + } + stage('Test'){ + steps { + sh 'make check' + junit 'reports/**/*.xml' + } + } + stage('Deploy') { + steps { + sh 'make publish' + } + } + } +} +``` \ No newline at end of file diff --git a/src/doc/examples/readme.md b/src/doc/examples/readme.md new file mode 100644 index 000000000..d94a626a6 --- /dev/null +++ b/src/doc/examples/readme.md @@ -0,0 +1,9 @@ +# Examples + +Examples of lockable resources include: + +If you have an example to share, please create a [new documentation issue](https://github.com/jenkinsci/lockable-resources-plugin/issues/new?assignees=&labels=documentation&template=3-documentation.yml) and provide additional examples as a [pull request](https://github.com/jenkinsci/lockable-resources-plugin/pulls) to the repository. +If you have a question, please open a [GitHub issue](https://github.com/jenkinsci/lockable-resources-plugin/issues/new/choose) with your question. + +- [Node depended resources](lock-nodes.md) +- [Locking multiple stages in declarative pipeline](locking-multiple-stages-in-declarative-pipeline.md) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties index 3df1e818b..525cdc1f7 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.properties @@ -60,8 +60,7 @@ The user can unreserve only own resource. Administrator can unreserve any resour btn.reassign=Reassign btn.reassign.detail=Reserves a resource that may be or not be reserved by some person already.
\ Giving it away to currently logged user indefinitely \ -(until that person, or some explicit scripted action, decides to release the resource).
\ -This action can be done only by administrator. +(until that person, or some explicit scripted action, decides to release the resource). btn.editNote=Note btn.editNote.detail=Edit resource note. #table labels From cb734eecd126cd48296fe9f73d642bf4bf910fef Mon Sep 17 00:00:00 2001 From: Pokorny Martin Date: Sun, 27 Nov 2022 23:56:58 +0100 Subject: [PATCH 0785/1078] eliminate duplicated code --- .../lockableresources/LockableResource.java | 32 +++++++++++++++---- .../LockableResourcesManager.java | 12 ++++--- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 12789469d..a28abaed6 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -157,6 +157,25 @@ public String getLabels() { return labels; } + /** + * Get labels of this resource + * @return List of assigned labels. + */ + @Exported + public List getLabelsAsList() { + return Arrays.asList(labels.split("\\s+")); + } + + /** + * Checks if the resource has label *labelToFind* + * @param labelToFind Label to find. + * @return {@code true} if this resource contains the label. + */ + @Exported + public boolean hasLabel(String labelToFind) { + return this.labelsContain(labelToFind); + } + @Exported public String getNote() { return this.note; @@ -181,12 +200,13 @@ public boolean isValidLabel(String candidate, Map params) { return labelsContain(candidate); } + /** + * Checks if the resource contain label *candidate*. + * @param candidate Labels to find. + * @return {@code true} if resource contains label *candidate* + */ private boolean labelsContain(String candidate) { - return makeLabelsList().contains(candidate); - } - - private List makeLabelsList() { - return Arrays.asList(labels.split("\\s+")); + return this.getLabelsAsList().contains(candidate); } /** @@ -205,7 +225,7 @@ public boolean scriptMatches( Binding binding = new Binding(params); binding.setVariable("resourceName", name); binding.setVariable("resourceDescription", description); - binding.setVariable("resourceLabels", makeLabelsList()); + binding.setVariable("resourceLabels", this.getLabelsAsList()); binding.setVariable("resourceNote", note); try { Object result = diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 9418f5798..1c56a13f2 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -147,9 +147,7 @@ public Boolean isValidLabel(String label) { public Set getAllLabels() { Set labels = new HashSet<>(); for (LockableResource r : this.resources) { - String rl = r.getLabels(); - if (rl == null || "".equals(rl)) continue; - labels.addAll(Arrays.asList(rl.split("\\s+"))); + labels.addAll(r.getLabelsAsList()); } return labels; } @@ -157,8 +155,12 @@ public Set getAllLabels() { public int getFreeResourceAmount(String label) { int free = 0; for (LockableResource r : this.resources) { - if (r.isLocked() || r.isQueued() || r.isReserved()) continue; - if (Arrays.asList(r.getLabels().split("\\s+")).contains(label)) free += 1; + if (r.isLocked() || r.isQueued() || r.isReserved()) { + continue; + } + if (r.hasLabel(label)) { + free ++; + } } return free; } From b4bfcde7fe78b940c2fd614011c4227d4739b6c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 27 Nov 2022 23:21:54 +0000 Subject: [PATCH 0786/1078] Bump bom-2.361.x from 1706.vc166d5f429f8 to 1723.vcb_9fee52c9fc Bumps [bom-2.361.x](https://github.com/jenkinsci/bom) from 1706.vc166d5f429f8 to 1723.vcb_9fee52c9fc. - [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.361.x 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 225c5356c..a483ecf73 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1706.vc166d5f429f8 + 1723.vcb_9fee52c9fc import pom From caacd42fabfe4aaad9cc08cfeae5f9c4f4b42922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helder=20Magalh=C3=A3es?= Date: Tue, 29 Nov 2022 17:40:30 +0000 Subject: [PATCH 0787/1078] Rename file to avoid 404 and also for consistency (#421) Broken link noticed in: https://github.com/jenkinsci/lockable-resources-plugin/blob/master/src/doc/examples/readme.md --- ...eline => locking-multiple-stages-in-declarative-pipeline.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/doc/examples/{locking-multiple-stages-in-declarative-pipeline => locking-multiple-stages-in-declarative-pipeline.md} (99%) diff --git a/src/doc/examples/locking-multiple-stages-in-declarative-pipeline b/src/doc/examples/locking-multiple-stages-in-declarative-pipeline.md similarity index 99% rename from src/doc/examples/locking-multiple-stages-in-declarative-pipeline rename to src/doc/examples/locking-multiple-stages-in-declarative-pipeline.md index e030fe85a..abe5d9aaa 100644 --- a/src/doc/examples/locking-multiple-stages-in-declarative-pipeline +++ b/src/doc/examples/locking-multiple-stages-in-declarative-pipeline.md @@ -30,4 +30,4 @@ options { } } } -``` \ No newline at end of file +``` From 50e4a751f3a4e59d371d536053cb25994e6f3816 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Dec 2022 19:01:15 +0000 Subject: [PATCH 0788/1078] Bump plugin from 4.51 to 4.52 Bumps [plugin](https://github.com/jenkinsci/plugin-pom) from 4.51 to 4.52. - [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/plugin-4.51...plugin-4.52) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin 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 a483ecf73..e22f9cc57 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.51 + 4.52 From 92cffb2e6d3e38aa53661bc44a56915f00a7eb94 Mon Sep 17 00:00:00 2001 From: Kyle Cronin Date: Wed, 7 Dec 2022 11:53:18 -0500 Subject: [PATCH 0789/1078] Switch action icon to lock symbol (#423) Update action icon to use built in Jenkins lock-closed symbol. --- .../actions/LockableResourcesRootAction.java | 2 +- src/main/webapp/img/device.svg | 139 ------------------ 2 files changed, 1 insertion(+), 140 deletions(-) delete mode 100644 src/main/webapp/img/device.svg diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 787710f53..80d5b369f 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -69,7 +69,7 @@ public class LockableResourcesRootAction implements RootAction { Jenkins.ADMINISTER, PermissionScope.JENKINS); - public static final String ICON = "/plugin/lockable-resources/img/device.svg"; + public static final String ICON = "symbol-lock-closed"; @Override public String getIconFileName() { diff --git a/src/main/webapp/img/device.svg b/src/main/webapp/img/device.svg deleted file mode 100644 index 312ca3253..000000000 --- a/src/main/webapp/img/device.svg +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From e994c3f0118713af990b49d671b3d48b0ecaa88c Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Wed, 7 Dec 2022 22:05:30 +0100 Subject: [PATCH 0790/1078] eliminate SemaphoreStep to make the tests more stable (faster) (#427) --- .../LockStepHardKillTest.java | 47 ++++++++++++++----- .../lockableresources/LockStepTest.java | 12 ++--- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index 7d25159dd..433c31b0d 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -25,18 +25,34 @@ public void hardKillNewBuildClearsLock() throws Exception { WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p1"); p1.setDefinition( new CpsFlowDefinition( - "lock('resource1') { echo 'locked!'; semaphore 'wait-inside'; echo 'Semaphore 1 unblocked'; }", true)); + "lock('resource1') {" + + " echo 'JOB 1 inside'\n" + + // this looks strange, but don not panic + // the job will be killed later + // I use here sleep instead of semaphore, because the + // semaphore step is very instable (slowly ?) + " sleep 600;" + + " echo 'JOB 1 unblocked';" + + "}", true)); WorkflowRun b1 = p1.scheduleBuild2(0).waitForStart(); - j.waitForMessage("locked!", b1); - SemaphoreStep.waitForStart("wait-inside/1", b1); + j.waitForMessage("JOB 1 inside", b1); WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "p2"); p2.setDefinition( new CpsFlowDefinition( - "lock('resource1') {\n" + - " semaphore 'wait-inside'\n" + - " echo 'Semaphore 2 unblocked'\n" + - "}", true)); + "try {\n" + + "lock('resource1') {\n" + + " echo 'JOB 2 inside'\n" + + // also here use long sleep time + // the job will be stopped later (but not killed) + " sleep 600;" + + "}\n" + + "}\n" + + "catch(error) {\n" + + " echo 'JOB 2 unblocked';\n"+ + " echo 'error:' + error;\n"+ + "}" + , true)); WorkflowRun b2 = p2.scheduleBuild2(0).waitForStart(); // Make sure that b2 is blocked on b1's lock. @@ -49,9 +65,10 @@ public void hardKillNewBuildClearsLock() throws Exception { p3.setDefinition( new CpsFlowDefinition( "lock('resource1') {\n" + - " semaphore 'wait-inside'\n" + - " echo 'Semaphore 3 unblocked'\n" + - "}", true)); + " echo 'JOB 3 inside'\n" + + "}\n" + + "echo 'JOB 3 unblocked'", + true)); WorkflowRun b3 = p3.scheduleBuild2(0).waitForStart(); // Make sure that b3 is also blocked still on b1's lock. @@ -66,15 +83,21 @@ public void hardKillNewBuildClearsLock() throws Exception { // Verify that b2 gets the lock. j.waitForMessage("Lock acquired on [resource1]", b2); - SemaphoreStep.success("wait-inside/2", b2); + j.waitForMessage("JOB 2 inside", b2); + j.assertLogNotContains("JOB 3 inside", b3); + + // terminate current step + b2.doTerm(); // Verify that b2 releases the lock and finishes successfully. j.waitForMessage("Lock released on resource [resource1]", b2); + j.waitForMessage("JOB 2 unblocked", b2); j.assertBuildStatusSuccess(j.waitForCompletion(b2)); isPaused(b2, 1, 0); // Now b3 should get the lock and do its thing. j.waitForMessage("Lock acquired on [resource1]", b3); - SemaphoreStep.success("wait-inside/3", b3); + j.waitForMessage("Lock released on resource [resource1]", b3); + j.waitForMessage("JOB 3 unblocked", b3); j.assertBuildStatusSuccess(j.waitForCompletion(b3)); isPaused(b3, 1, 0); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 29164ae7a..0590f7ff5 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -516,18 +516,16 @@ public void manualUnreserveUnblocksJob() throws Exception { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "retry(99) {\n" - + " lock('resource1') {\n" - + " semaphore('wait-inside')\n" - + " }\n" - + "}", + "lock('resource1') {\n" + + " echo('I am inside')\n" + + "}\n", true)); WorkflowRun r = p.scheduleBuild2(0).waitForStart(); j.waitForMessage("[resource1] is locked, waiting...", r); + j.assertLogNotContains("I am inside", r); TestHelpers.clickButton(wc, "unreserve"); - SemaphoreStep.waitForStart("wait-inside/1", r); - SemaphoreStep.success("wait-inside/1", null); + j.waitForMessage("I am inside", r); j.assertBuildStatusSuccess(j.waitForCompletion(r)); } From 03fd104d44aa41680925686b1ee89a21194320cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 19:01:03 +0000 Subject: [PATCH 0791/1078] Bump crowdin/github-action from 1.5.1 to 1.5.2 Bumps [crowdin/github-action](https://github.com/crowdin/github-action) from 1.5.1 to 1.5.2. - [Release notes](https://github.com/crowdin/github-action/releases) - [Commits](https://github.com/crowdin/github-action/compare/1.5.1...1.5.2) --- updated-dependencies: - dependency-name: crowdin/github-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 9e681169b..cd6d6af4c 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 - name: crowdin action - uses: crowdin/github-action@1.5.1 + uses: crowdin/github-action@1.5.2 with: upload_translations: false download_translations: true From c78c6cd7f35dfb54d5a133a5c90d2854e62da35f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 19:01:08 +0000 Subject: [PATCH 0792/1078] Bump plugin from 4.52 to 4.53 Bumps [plugin](https://github.com/jenkinsci/plugin-pom) from 4.52 to 4.53. - [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/plugin-4.52...plugin-4.53) --- updated-dependencies: - dependency-name: org.jenkins-ci.plugins:plugin 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 e22f9cc57..3ce787110 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.52 + 4.53 From 47136e4a0eb53766bffcb15395c0c5f64346fcec Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Mon, 12 Dec 2022 20:26:53 +0100 Subject: [PATCH 0793/1078] chore(dependencies) Require 2.361.4 as minimum Jenkins version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3ce787110..907a32121 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ - 999999-SNAPSHOT - 2.361.1 + 999999-SNAPSHOT + 2.361.4 jenkinsci/${project.artifactId}-plugin Max Low From 01a218120636606ff87fb25f30041fe7a611369b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 19:49:09 +0000 Subject: [PATCH 0794/1078] Bump bom-2.361.x from 1723.vcb_9fee52c9fc to 1742.vb_70478c1b_25f Bumps [bom-2.361.x](https://github.com/jenkinsci/bom) from 1723.vcb_9fee52c9fc to 1742.vb_70478c1b_25f. - [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.361.x 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 907a32121..ef02c3b8d 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1723.vcb_9fee52c9fc + 1742.vb_70478c1b_25f import pom From 78bf92d97df246fd0192cab352c6049dd6c1dcdb Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Mon, 12 Dec 2022 21:02:33 +0100 Subject: [PATCH 0795/1078] chore(dependencies) Move to jenkins 2.361.4 --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index cc8d42c72..964cdb4ce 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,10 +4,10 @@ */ buildPlugin(useContainerAgent: true, configurations: [ // Test the common case (i.e., a recent LTS release) on both Linux and Windows. - [ platform: 'linux', jdk: '11', jenkins: '2.361.1' ], - [ platform: 'windows', jdk: '11', jenkins: '2.361.1' ], + [ platform: 'linux', jdk: '11', jenkins: '2.361.4' ], + [ platform: 'windows', jdk: '11', jenkins: '2.361.4' ], // Test the bleeding edge of the compatibility spectrum (i.e., the latest supported Java runtime). // see also https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ - [ platform: 'linux', jdk: '17', jenkins: '2.361.2' ], + [ platform: 'linux', jdk: '17', jenkins: '2.361.4' ], ]) From e567879727959e66751e3c8955ee72e7d28011a9 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Sat, 17 Dec 2022 11:24:49 -0800 Subject: [PATCH 0796/1078] Remove unnecessary dependency --- pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pom.xml b/pom.xml index ef02c3b8d..b5dbd1c08 100644 --- a/pom.xml +++ b/pom.xml @@ -109,18 +109,6 @@ org.jenkins-ci.plugins script-security
- - com.infradna.tool - bridge-method-annotation - 1.25 - provided - - - org.jenkins-ci - annotation-indexer - - - io.jenkins.plugins data-tables-api From 1e92c0c1dfa9a6282aba1f8776469140e955a2ef Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 18 Dec 2022 17:15:57 +0100 Subject: [PATCH 0797/1078] Export hardcoded java errors into properties (#418) Export hardcoded java errors into properties --- .../plugins/lockableresources/LockStep.java | 2 +- .../lockableresources/LockStepResource.java | 12 ++++++------ .../lockableresources/LockableResource.java | 2 +- .../LockableResourcesManager.java | 2 +- .../RequiredResourcesProperty.java | 16 +++++++--------- .../actions/LockableResourcesRootAction.java | 16 ++++++++-------- .../lockableresources/Messages.properties | 16 +++++++++++++++- .../plugins/lockableresources/LockStepTest.java | 2 +- .../LockableResourceManagerTest.java | 12 ++++++------ 9 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java index 6a9cca988..7577885a4 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStep.java @@ -98,7 +98,7 @@ public String getFunctionName() { @NonNull @Override public String getDisplayName() { - return "Lock shared resource"; + return Messages.LockStep_displayName(); } @Override diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java index c89e80dfa..cc4f82d3a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepResource.java @@ -86,10 +86,10 @@ public void validate() { */ public static void validate(String resource, String label, int quantity) { if (label != null && !label.isEmpty() && resource != null && !resource.isEmpty()) { - throw new IllegalArgumentException("Label and resource name cannot be specified simultaneously."); + throw new IllegalArgumentException(Messages.error_labelAndNameSpecified()); } if (label != null && !LockableResourcesManager.get().isValidLabel( label ) ) { - throw new IllegalArgumentException("The label does not exist: " + label); + throw new IllegalArgumentException(Messages.error_labelDoesNotExist(label)); } } @@ -101,7 +101,7 @@ public static class DescriptorImpl extends Descriptor { @NonNull @Override public String getDisplayName() { - return "Resource"; + return Messages.LockStepResource_displayName(); } @RequirePOST @@ -124,13 +124,13 @@ public static FormValidation doCheckLabel(@QueryParameter String value, String resourceLabel = Util.fixEmpty(value); String resourceName = Util.fixEmpty(resource); if (resourceLabel != null && resourceName != null) { - return FormValidation.error("Label and resource name cannot be specified simultaneously."); + return FormValidation.error(Messages.error_labelAndNameSpecified()); } if ((resourceLabel == null) && (resourceName == null)) { - return FormValidation.error("Either label or resource name must be specified."); + return FormValidation.error(Messages.error_labelOrNameMustBeSpecified()); } if (resourceLabel != null && !LockableResourcesManager.get().isValidLabel(resourceLabel)) { - return FormValidation.error("The label does not exist: " + resourceLabel); + return FormValidation.error(Messages.error_labelDoesNotExist(resourceLabel)); } return FormValidation.ok(); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index a28abaed6..e50eefee4 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -475,7 +475,7 @@ public static class DescriptorImpl extends Descriptor { @NonNull @Override public String getDisplayName() { - return "Resource"; + return Messages.LockableResource_displayName(); } } } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 1c56a13f2..e7a19e9ea 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -865,7 +865,7 @@ public synchronized void unreserve(List resources) { @NonNull @Override public String getDisplayName() { - return "External Resources"; + return Messages.LockableResourcesManager_displayName(); } public synchronized void reset(List resources) { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java index 5a720143a..4f27d9c82 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/RequiredResourcesProperty.java @@ -137,7 +137,7 @@ public static class DescriptorImpl extends JobPropertyDescriptor { @NonNull @Override public String getDisplayName() { - return "Required Lockable Resources"; + return Messages.RequiredResourcesProperty_displayName(); } @Override @@ -167,8 +167,7 @@ public FormValidation doCheckResourceNames(@QueryParameter String value, if (names == null) { return FormValidation.ok(); } else if (labelVal != null || script) { - return FormValidation.error( - "Only label, groovy expression, or resources can be defined, not more than one."); + return FormValidation.error(Messages.error_labelAndNameOrGroovySpecified()); } else { List wrongNames = new ArrayList<>(); for (String name : names.split("\\s+")) { @@ -187,8 +186,7 @@ public FormValidation doCheckResourceNames(@QueryParameter String value, return FormValidation.ok(); } else { return FormValidation - .error("The following resources do not exist: " - + wrongNames); + .error(Messages.error_resourceDoesNotExist(wrongNames)); } } } @@ -209,13 +207,13 @@ public FormValidation doCheckLabelName( return FormValidation.ok(); } else if (names != null || script) { return FormValidation.error( - "Only label, groovy expression, or resources can be defined, not more than one."); + Messages.error_labelAndNameOrGroovySpecified()); } else { if (LockableResourcesManager.get().isValidLabel(label)) { return FormValidation.ok(); } else { return FormValidation.error( - "The label does not exist: " + label); + Messages.error_labelDoesNotExist(label)); } } } @@ -243,7 +241,7 @@ public FormValidation doCheckResourceNumber(@QueryParameter String value, numAsInt = Integer.parseInt(number); } catch(NumberFormatException e) { return FormValidation.error( - "Could not parse the given value as integer."); + Messages.error_couldNotParseToint()); } int numResources = 0; if (names != null) { @@ -254,7 +252,7 @@ public FormValidation doCheckResourceNumber(@QueryParameter String value, if (numResources < numAsInt) { return FormValidation.error(String.format( - "Given amount %d is greater than amount of resources: %d.", + Messages.error_givenAmountIsGreaterThatResurcesAmount(), numAsInt, numResources)); } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 80d5b369f..000af1164 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -171,7 +171,7 @@ public void doUnlock(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -191,7 +191,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -200,7 +200,7 @@ public void doReserve(StaplerRequest req, StaplerResponse rsp) String userName = getUserName(); if (userName != null) { if (!LockableResourcesManager.get().reserve(resources, userName)) { - rsp.sendError(423, "Resource '" + name + "' already reserved or locked!"); + rsp.sendError(423, Messages.error_resourceAlreadyLocked(name)); return; } } @@ -216,7 +216,7 @@ public void doSteal(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -246,7 +246,7 @@ public void doReassign(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -274,7 +274,7 @@ public void doUnreserve(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -302,7 +302,7 @@ public void doReset(StaplerRequest req, StaplerResponse rsp) String name = req.getParameter("resource"); LockableResource r = LockableResourcesManager.get().fromName(name); if (r == null) { - rsp.sendError(404, "Resource not found " + name); + rsp.sendError(404, Messages.error_resourceDoesNotExist(name)); return; } @@ -325,7 +325,7 @@ public void doSaveNote(final StaplerRequest req, final StaplerResponse rsp) final LockableResource resource = getResource(resourceName); if (resource == null) { - rsp.sendError(404, "Resource not found: '" + resourceName + "'!"); + rsp.sendError(404, Messages.error_resourceDoesNotExist(resourceName)); } else { String resourceNote = req.getParameter("note"); if (resourceNote == null) { diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties index 23f8110ec..13dc7a0a2 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties @@ -20,4 +20,18 @@ LockableResourcesRootAction.StealPermission.Description=This permission grants t LockableResourcesRootAction.ViewPermission=View LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view \ lockable resources. - +# Java errors +error.labelDoesNotExist=The resource label does not exist: {0}. +error.resourceDoesNotExist=The resource does not exist: {0}. +error.labelOrNameMustBeSpecified=Either resource label or resource name must be specified. +error.labelAndNameSpecified=Resource label and resource name cannot be specified simultaneously. +error.labelAndNameOrGroovySpecified=Only resource label, groovy expression, or resource names can be defined, not more than one. +error.couldNotParseToint=Could not parse the given value as integer. +error.givenAmountIsGreaterThatResurcesAmount=Given amount %d is greater than amount of resources: %d. +error.resourceAlreadyLocked=Resource {0} already reserved or locked! +# display-names +LockStep.displayName=Lock shared resource +LockStepResource.displayName=Resource +LockableResource.displayName=Resource +LockableResourcesManager.displayName=External Resources +RequiredResourcesProperty.displayName=Required Lockable Resources diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java index 0590f7ff5..713d06a18 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepTest.java @@ -1432,7 +1432,7 @@ public void lockWithInvalidLabel() throws Exception { WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); j.waitForCompletion(b1); j.assertBuildStatus(Result.FAILURE, b1); - j.assertLogContains("The label does not exist: invalidLabel", b1); + j.assertLogContains("The resource label does not exist: invalidLabel", b1); isPaused(b1, 0, 0); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java index 48d2f3376..cab9283b5 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceManagerTest.java @@ -28,22 +28,22 @@ public void validationFailure() throws Exception { r.setLabels("some-label"); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckResourceNames("resource1", null, true, null).getMessage()); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckResourceNames("resource1", "some-label", false, null).getMessage()); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckResourceNames("resource1", "some-label", true, null).getMessage()); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckLabelName("some-label", "resource1", false, null).getMessage()); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckLabelName("some-label", null, true, null).getMessage()); assertEquals( - "Only label, groovy expression, or resources can be defined, not more than one.", + "Only resource label, groovy expression, or resource names can be defined, not more than one.", d.doCheckLabelName("some-label", "resource1", true, null).getMessage()); assertEquals(FormValidation.ok(), d.doCheckResourceNames("resource1", null, false, null)); From cbeb0a030f0a01ac858b5a2d1186808ce160ffb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 19:38:13 +0000 Subject: [PATCH 0798/1078] Bump bom-2.361.x from 1742.vb_70478c1b_25f to 1750.v0071fa_4c4a_e3 (#433) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b5dbd1c08..51fa7014f 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1742.vb_70478c1b_25f + 1750.v0071fa_4c4a_e3 import pom From de5663d777cff65a950d8f580d1301e55999d486 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Tue, 20 Dec 2022 06:35:08 +0100 Subject: [PATCH 0799/1078] Store table order and paging size a user select (#415) Store table order and paging size a user select --- .../lockableresources/LockableResource.java | 103 +++-- .../LockableResourcesManager.java | 10 +- .../actions/LockableResourcesRootAction.java | 8 +- .../LockStep/config_af.properties | 30 -- .../LockStep/config_ar.properties | 30 -- .../LockStep/config_ca.properties | 30 -- .../LockStep/config_da.properties | 30 -- .../LockStep/config_el.properties | 30 -- .../LockStep/config_en.properties | 30 -- .../LockStep/config_es.properties | 30 -- .../LockStep/config_fi.properties | 30 -- .../LockStep/config_he.properties | 30 -- .../LockStep/config_hu.properties | 30 -- .../LockStep/config_it.properties | 30 -- .../LockStep/config_ja.properties | 30 -- .../LockStep/config_ko.properties | 30 -- .../LockStep/config_nl.properties | 30 -- .../LockStep/config_no.properties | 30 -- .../LockStep/config_pl.properties | 30 -- .../LockStep/config_pt.properties | 30 -- .../LockStep/config_ro.properties | 30 -- .../LockStep/config_ru.properties | 30 -- .../LockStep/config_sr.properties | 30 -- .../LockStep/config_sv.properties | 30 -- .../LockStep/config_tr.properties | 30 -- .../LockStep/config_uk.properties | 30 -- .../LockStep/config_vi.properties | 30 -- .../LockStep/config_zh.properties | 30 -- .../LockStepResource/config_el.properties | 25 -- .../LockStepResource/config_en.properties | 25 -- .../LockStepResource/config_es.properties | 25 -- .../LockStepResource/config_fi.properties | 25 -- .../LockStepResource/config_he.properties | 25 -- .../LockStepResource/config_hu.properties | 25 -- .../LockStepResource/config_it.properties | 25 -- .../LockStepResource/config_ja.properties | 25 -- .../LockStepResource/config_ko.properties | 25 -- .../LockStepResource/config_nl.properties | 25 -- .../LockStepResource/config_no.properties | 25 -- .../LockStepResource/config_pl.properties | 25 -- .../LockStepResource/config_pt.properties | 25 -- .../LockStepResource/config_ro.properties | 25 -- .../LockStepResource/config_ru.properties | 25 -- .../LockStepResource/config_sr.properties | 25 -- .../LockStepResource/config_sv.properties | 25 -- .../LockStepResource/config_tr.properties | 25 -- .../LockStepResource/config_uk.properties | 25 -- .../LockStepResource/config_vi.properties | 25 -- .../LockStepResource/config_zh.properties | 25 -- .../LockableResource/config_af.properties | 26 -- .../LockableResource/config_ar.properties | 26 -- .../LockableResource/config_ca.properties | 26 -- .../LockableResource/config_da.properties | 26 -- .../LockableResource/config_el.properties | 26 -- .../LockableResource/config_en.properties | 26 -- .../LockableResource/config_es.properties | 26 -- .../LockableResource/config_fi.properties | 26 -- .../LockableResource/config_he.properties | 26 -- .../LockableResource/config_hu.properties | 26 -- .../LockableResource/config_it.properties | 26 -- .../LockableResource/config_ja.properties | 26 -- .../LockableResource/config_ko.properties | 26 -- .../LockableResource/config_nl.properties | 26 -- .../LockableResource/config_no.properties | 26 -- .../LockableResource/config_pl.properties | 26 -- .../LockableResource/config_pt.properties | 26 -- .../LockableResource/config_ro.properties | 26 -- .../LockableResource/config_ru.properties | 26 -- .../LockableResource/config_sr.properties | 26 -- .../LockableResource/config_sv.properties | 26 -- .../LockableResource/config_tr.properties | 26 -- .../LockableResource/config_uk.properties | 26 -- .../LockableResource/config_vi.properties | 26 -- .../LockableResource/config_zh.properties | 26 -- .../config_af.properties | 26 -- .../config_ar.properties | 26 -- .../config_ca.properties | 26 -- .../config_da.properties | 26 -- .../config_el.properties | 26 -- .../config_en.properties | 26 -- .../config_es.properties | 26 -- .../config_fi.properties | 26 -- .../config_he.properties | 26 -- .../config_hu.properties | 26 -- .../config_it.properties | 26 -- .../config_ja.properties | 26 -- .../config_ko.properties | 26 -- .../config_nl.properties | 26 -- .../config_no.properties | 26 -- .../config_pl.properties | 26 -- .../config_pt.properties | 26 -- .../config_ro.properties | 26 -- .../config_ru.properties | 26 -- .../config_sr.properties | 26 -- .../config_sv.properties | 26 -- .../config_tr.properties | 26 -- .../config_uk.properties | 26 -- .../config_vi.properties | 26 -- .../config_zh.properties | 26 -- .../lockableresources/Messages_af.properties | 19 - .../lockableresources/Messages_ar.properties | 19 - .../lockableresources/Messages_ca.properties | 19 - .../lockableresources/Messages_da.properties | 19 - .../lockableresources/Messages_el.properties | 19 - .../lockableresources/Messages_en.properties | 19 - .../lockableresources/Messages_es.properties | 19 - .../lockableresources/Messages_fi.properties | 19 - .../lockableresources/Messages_he.properties | 19 - .../lockableresources/Messages_hu.properties | 19 - .../lockableresources/Messages_it.properties | 19 - .../lockableresources/Messages_ja.properties | 19 - .../lockableresources/Messages_ko.properties | 19 - .../lockableresources/Messages_nl.properties | 19 - .../lockableresources/Messages_no.properties | 19 - .../lockableresources/Messages_pl.properties | 19 - .../lockableresources/Messages_pt.properties | 19 - .../lockableresources/Messages_ro.properties | 19 - .../lockableresources/Messages_ru.properties | 19 - .../lockableresources/Messages_sr.properties | 19 - .../lockableresources/Messages_sv.properties | 19 - .../lockableresources/Messages_tr.properties | 19 - .../lockableresources/Messages_uk.properties | 19 - .../lockableresources/Messages_vi.properties | 19 - .../lockableresources/Messages_zh.properties | 19 - .../config_af.properties | 28 -- .../config_ar.properties | 28 -- .../config_ca.properties | 28 -- .../config_da.properties | 28 -- .../config_el.properties | 28 -- .../config_en.properties | 28 -- .../config_es.properties | 28 -- .../config_fi.properties | 28 -- .../config_he.properties | 28 -- .../config_hu.properties | 28 -- .../config_it.properties | 28 -- .../config_ja.properties | 28 -- .../config_ko.properties | 28 -- .../config_nl.properties | 28 -- .../config_no.properties | 28 -- .../config_pl.properties | 28 -- .../config_pt.properties | 28 -- .../config_ro.properties | 28 -- .../config_ru.properties | 28 -- .../config_sr.properties | 28 -- .../config_sv.properties | 28 -- .../config_tr.properties | 28 -- .../config_uk.properties | 28 -- .../config_vi.properties | 28 -- .../config_zh.properties | 28 -- .../LockableResourcesRootAction/index.jelly | 360 +----------------- .../index.properties | 43 --- .../index_ar.properties | 64 ---- .../index_ca.properties | 64 ---- .../index_cs.properties | 37 -- .../index_da.properties | 64 ---- .../index_de.properties | 37 -- .../index_el.properties | 64 ---- .../index_en.properties | 64 ---- .../index_es.properties | 64 ---- .../index_fi.properties | 64 ---- .../index_fr.properties | 37 -- .../index_he.properties | 64 ---- .../index_hu.properties | 64 ---- .../index_it.properties | 64 ---- .../index_ja.properties | 64 ---- .../index_ko.properties | 64 ---- .../index_nl.properties | 64 ---- .../index_no.properties | 64 ---- .../index_pl.properties | 64 ---- .../index_pt.properties | 64 ---- .../index_ro.properties | 64 ---- .../index_ru.properties | 64 ---- .../index_sk.properties | 37 -- .../index_sr.properties | 64 ---- .../index_sv.properties | 64 ---- .../index_tr.properties | 64 ---- .../index_uk.properties | 64 ---- .../index_vi.properties | 64 ---- .../index_zh.properties | 64 ---- .../noteForm.jelly | 2 +- .../tableLabels/table.jelly | 98 +++++ .../tableLabels/table.properties} | 10 +- .../tableLabels/table_cs.properties} | 10 +- .../tableLabels/table_de.properties} | 10 +- .../tableLabels/table_fr.properties} | 10 +- .../tableLabels/table_sk.properties | 29 ++ .../tableResources/table.jelly | 292 ++++++++++++++ .../table.properties} | 39 +- .../tableResources/table_cs.properties | 55 +++ .../tableResources/table_de.properties | 55 +++ .../tableResources/table_fr.properties | 55 +++ .../tableResources/table_sk.properties | 55 +++ .../index_af.properties | 24 -- .../index_ar.properties | 24 -- .../index_ca.properties | 24 -- .../index_da.properties | 24 -- .../index_el.properties | 24 -- .../index_en.properties | 24 -- .../index_es.properties | 24 -- .../index_fi.properties | 24 -- .../index_he.properties | 24 -- .../index_hu.properties | 24 -- .../index_it.properties | 24 -- .../index_ja.properties | 24 -- .../index_ko.properties | 24 -- .../index_nl.properties | 24 -- .../index_no.properties | 24 -- .../index_pl.properties | 24 -- .../index_pt.properties | 24 -- .../index_ro.properties | 24 -- .../index_ru.properties | 24 -- .../index_sr.properties | 24 -- .../index_sv.properties | 24 -- .../index_tr.properties | 24 -- .../index_uk.properties | 24 -- .../index_vi.properties | 24 -- .../index_zh.properties | 24 -- src/main/webapp/css/style.css | 21 + src/main/webapp/js/lockable-resources.js | 26 +- .../lockableresources/LockStepTest.java | 34 -- ...ckStepTest_manualUnreserveUnblocksJob.java | 57 +++ ...ockStepTest_reserveInsideLockHonoured.java | 249 ++++++++++++ ...pTest_setReservedByInsideLockHonoured.java | 226 +++++++++++ .../LockableResourcesRootActionTest.java | 10 +- 224 files changed, 1348 insertions(+), 6553 deletions(-) delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/Messages_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_zh.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index_zh.properties create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table.jelly rename src/main/resources/org/jenkins/plugins/lockableresources/{LockStepResource/config_af.properties => actions/LockableResourcesRootAction/tableLabels/table.properties} (84%) rename src/main/resources/org/jenkins/plugins/lockableresources/{LockStepResource/config_da.properties => actions/LockableResourcesRootAction/tableLabels/table_cs.properties} (82%) rename src/main/resources/org/jenkins/plugins/lockableresources/{LockStepResource/config_ar.properties => actions/LockableResourcesRootAction/tableLabels/table_de.properties} (84%) rename src/main/resources/org/jenkins/plugins/lockableresources/{LockStepResource/config_ca.properties => actions/LockableResourcesRootAction/tableLabels/table_fr.properties} (82%) create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table_sk.properties create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly rename src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/{index_af.properties => tableResources/table.properties} (59%) create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_cs.properties create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_de.properties create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_fr.properties create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_sk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_af.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ar.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ca.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_da.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_el.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_en.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_es.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_fi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_he.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_hu.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_it.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ja.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ko.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_nl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_no.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_pl.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_pt.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ro.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_ru.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_sr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_sv.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_tr.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_uk.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_vi.properties delete mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index_zh.properties create mode 100644 src/main/webapp/css/style.css create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepTest_manualUnreserveUnblocksJob.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepTest_reserveInsideLockHonoured.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/LockStepTest_setReservedByInsideLockHonoured.java diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index e50eefee4..cde8dbe27 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -30,7 +30,6 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; @@ -58,7 +57,7 @@ public class LockableResource extends AbstractDescribableImpl private final String name; private String description = ""; - private String labels = ""; + private List labels = new ArrayList<>(); private String reservedBy = null; private Date reservedTimestamp = null; private String note = ""; @@ -106,16 +105,20 @@ public class LockableResource extends AbstractDescribableImpl @Deprecated @ExcludeFromJacocoGeneratedReport public LockableResource(String name, String description, String labels, String reservedBy, String note) { + // todo throw exception, when the name is empty + // todo check if the name contains only valid characters (no spaces, new lines ...) this.name = name; - this.description = description; - this.labels = labels; - this.reservedBy = Util.fixEmptyAndTrim(reservedBy); - this.note = note; + this.setDescription(description); + this.setLabels(labels); + this.setReservedBy(reservedBy); + this.setNote(note); } @DataBoundConstructor public LockableResource(String name) { - this.name = name; + this.name = Util.fixNull(name); + // todo throw exception, when the name is empty + // todo check if the name contains only valid characters (no spaces, new lines ...) } protected Object readResolve() { @@ -132,29 +135,56 @@ public List getQueuedContexts() { return this.queuedContexts; } + @Exported + public String getName() { + return name; + } + + @Exported + public String getDescription() { + return description; + } + @DataBoundSetter public void setDescription(String description) { - this.description = description; + this.description = Util.fixNull(description); + } + + @Exported + public String getNote() { + return this.note; } @DataBoundSetter - public void setLabels(String labels) { - this.labels = labels; + public void setNote(String note) { + this.note = Util.fixNull(note); } - @Exported - public String getName() { - return name; + @DataBoundSetter + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; } @Exported - public String getDescription() { - return description; + public boolean isEphemeral() { + return ephemeral; } @Exported public String getLabels() { - return labels; + return String.join(" ", this.labels); + } + + @DataBoundSetter + public void setLabels(String labels) { + // todo use label parser from Jenkins.Label to allow the same syntax + this.labels = new ArrayList<>(); + for(String label : labels.split("\\s+")) { + if (label == null || label.isEmpty()) { + continue; + } + this.labels.add(label); + } } /** @@ -163,7 +193,7 @@ public String getLabels() { */ @Exported public List getLabelsAsList() { - return Arrays.asList(labels.split("\\s+")); + return this.labels; } /** @@ -176,26 +206,6 @@ public boolean hasLabel(String labelToFind) { return this.labelsContain(labelToFind); } - @Exported - public String getNote() { - return this.note; - } - - @DataBoundSetter - public void setNote(String note) { - this.note = note; - } - - @DataBoundSetter - public void setEphemeral(boolean ephemeral) { - this.ephemeral = ephemeral; - } - - @Exported - public boolean isEphemeral() { - return ephemeral; - } - public boolean isValidLabel(String candidate, Map params) { return labelsContain(candidate); } @@ -268,6 +278,25 @@ public boolean isReserved() { return reservedBy != null; } + @Restricted(NoExternalUse.class) + public static String getUserName() { + User current = User.current(); + if (current != null) { + return current.getFullName(); + } else { + return null; + } + } + + /** + * Function check if the resources is reserved by currently logged user + * @return true when reserved by current user, false otherwise. + */ + @Restricted(NoExternalUse.class) // called by jelly + public boolean isReservedByCurrentUser() { + return (this.reservedBy != null && getUserName().equals(this.reservedBy)); + } + @Exported public String getReservedByEmail() { if (isReserved()) { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index e7a19e9ea..6e185ae1a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -18,10 +18,10 @@ import hudson.Extension; import hudson.model.Run; import hudson.model.TaskListener; +import hudson.Util; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -147,7 +147,11 @@ public Boolean isValidLabel(String label) { public Set getAllLabels() { Set labels = new HashSet<>(); for (LockableResource r : this.resources) { - labels.addAll(r.getLabelsAsList()); + List toAdd = r.getLabelsAsList(); + if (toAdd.isEmpty()) { + continue; + } + labels.addAll(toAdd); } return labels; } @@ -672,6 +676,7 @@ private QueuedContextStruct getNextQueuedContext( /** Creates the resource if it does not exist. */ public synchronized boolean createResource(String name) { + name = Util.fixEmptyAndTrim(name); if (name != null) { LockableResource existent = fromName(name); if (existent == null) { @@ -686,6 +691,7 @@ public synchronized boolean createResource(String name) { } public synchronized boolean createResourceWithLabel(String name, String label) { + name = Util.fixEmptyAndTrim(name); if (name != null && label != null) { LockableResource existent = fromName(name); if (existent == null) { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java index 000af1164..b5e872cb3 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction.java @@ -11,7 +11,6 @@ import hudson.Extension; import hudson.model.Api; import hudson.model.RootAction; -import hudson.model.User; import hudson.security.AccessDeniedException3; import hudson.security.Permission; import hudson.security.PermissionGroup; @@ -81,12 +80,7 @@ public Api getApi() { } public String getUserName() { - User current = User.current(); - if (current != null) { - return current.getFullName(); - } else { - return null; - } + return LockableResource.getUserName(); } @Override diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_af.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_af.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ar.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ar.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ca.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ca.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_da.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_da.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_el.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_el.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_en.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_en.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_es.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_es.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_fi.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_fi.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_he.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_he.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_hu.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_hu.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_it.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_it.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ja.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ja.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ko.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ko.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_nl.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_nl.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_no.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_no.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pl.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pl.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pt.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_pt.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ro.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ro.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ru.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_ru.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sr.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sr.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sv.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_sv.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_tr.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_tr.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_uk.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_uk.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_vi.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_vi.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_zh.properties deleted file mode 100644 index 30ed0073a..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/config_zh.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity -entry.variable.title=Result variable -entry.inversePrecedence.checkbox.title=Inverse precedence -entry.inversePrecedence.skipIfLocked.title=Skip queue -entry.extra.title=Extra resources -entry.extra.add=Add Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_el.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_el.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_en.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_en.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_es.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_es.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_fi.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_fi.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_he.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_he.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_hu.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_hu.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_it.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ja.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ja.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ko.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ko.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_nl.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_nl.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_no.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_no.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pl.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pl.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pt.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_pt.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ro.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ro.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ru.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_ru.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sr.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sr.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sv.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_sv.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_tr.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_tr.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_uk.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_uk.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_vi.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_vi.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_zh.properties deleted file mode 100644 index 90154a2db..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/config_zh.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.resource.title=Resource -entry.label.title=Label -entry.quantity.title=Quantity \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_af.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_af.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ar.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ar.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ca.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ca.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_da.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_da.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_el.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_el.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_en.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_en.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_es.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_es.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_fi.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_fi.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_he.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_he.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_hu.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_hu.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_it.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_it.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ja.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ja.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ko.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ko.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_nl.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_nl.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_no.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_no.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pl.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pl.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pt.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_pt.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ro.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ro.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ru.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_ru.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sr.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sr.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sv.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_sv.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_tr.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_tr.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_uk.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_uk.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_vi.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_vi.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_zh.properties deleted file mode 100644 index 7764bb1dd..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config_zh.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -entry.name.title=Name -entry.description.title=Description -entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_af.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_af.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ar.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ar.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ca.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ca.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_da.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_da.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_el.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_el.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_en.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_en.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_es.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_es.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_fi.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_fi.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_he.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_he.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_hu.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_hu.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_it.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_it.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ja.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ja.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ko.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ko.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_nl.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_nl.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_no.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_no.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pl.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pl.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pt.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_pt.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ro.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ro.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ru.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_ru.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sr.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sr.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sv.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_sv.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_tr.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_tr.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_uk.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_uk.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_vi.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_vi.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_zh.properties deleted file mode 100644 index 90e00ed6c..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourcesManager/config_zh.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -section.title=Lockable Resources Manager -entry.title=Lockable Resources -field.header=Resource -field.add=Add Lockable Resource \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_af.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_af.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ar.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ar.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ca.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ca.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_da.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_da.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_el.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_el.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_en.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_en.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_es.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_es.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fi.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_fi.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_he.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_he.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_hu.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_hu.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_it.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_it.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ja.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ja.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ko.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ko.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_nl.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_nl.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_no.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_no.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pl.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pl.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pt.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_pt.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ro.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ro.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ru.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_ru.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sr.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sr.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sv.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_sv.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_tr.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_tr.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_uk.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_uk.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_vi.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_vi.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages_zh.properties deleted file mode 100644 index 1fb507228..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages_zh.properties +++ /dev/null @@ -1,19 +0,0 @@ -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # -# Copyright (c) 2014, 6WIND S.A. All rights reserved. # -# # -# This file is part of the Jenkins Lockable Resources Plugin and is # -# published under the MIT license. # -# # -# See the "LICENSE.txt" file for more information. # -# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # - -LockableResourcesRootAction.PermissionGroup=Lockable Resources -LockableResourcesRootAction.UnlockPermission=Unlock -LockableResourcesRootAction.UnlockPermission.Description=This permission grants the ability to manually unlock resources that have been locked by builds. -LockableResourcesRootAction.ReservePermission=Reserve -LockableResourcesRootAction.ReservePermission.Description=This permission grants the ability to manually reserve lockable resources outside of a build. -LockableResourcesRootAction.StealPermission=Steal -LockableResourcesRootAction.StealPermission.Description=This permission grants the ability to manually "steal" resources that have been locked by builds or "reassign" those reserved by users. -LockableResourcesRootAction.ViewPermission=View -LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view lockable resources. - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_af.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_af.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_af.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ar.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ar.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ar.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ca.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ca.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ca.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_da.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_da.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_da.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_el.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_el.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_el.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_en.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_en.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_en.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_es.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_es.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_es.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_fi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_fi.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_fi.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_he.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_he.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_he.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_hu.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_hu.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_hu.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_it.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_it.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_it.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ja.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ja.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ja.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ko.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ko.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ko.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_nl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_nl.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_nl.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_no.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_no.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_no.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pl.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pl.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pl.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pt.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pt.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_pt.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ro.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ro.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ro.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ru.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ru.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_ru.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sr.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sr.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sv.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sv.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_sv.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_tr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_tr.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_tr.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_uk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_uk.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_uk.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_vi.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_vi.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_vi.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_zh.properties b/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_zh.properties deleted file mode 100644 index d745faf83..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/RequiredResourcesProperty/config_zh.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright 2022 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -optionalBlock.title=This build requires lockable resources -entry.resourceNames.title=Resources -entry.labelName.title=Label -optionalProperty.resourceMatchScript.title=Groovy Expression -entry.resourceNamesVar.title=Reserved resources variable name -entry.resourceNumber.title=Number of resources to request \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly index 464647309..e0e1a909f 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/index.jelly @@ -16,352 +16,26 @@ xmlns:st="jelly:stapler" > - - - - -

${%header.labels}

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
${%labels.table.column.labels}${%labels.table.column.free}${%labels.table.column.assigned}
- ${label} - - ${freeCount} - - ${allCount} -
- -
-
- -
+ +

${%queue.warning.count(queue.size(), h.getTimeSpanString(oldestQueue.getQueuedTimestamp()))}

+
${%queue.warning.count.detail}
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
${%queue.table.column.request.type}${%queue.table.column.request.info}${%queue.table.column.requested.by}${%queue.table.column.requested.at}${%queue.table.column.reason}
+ + + ${build.fullDisplayName} + + + ${%N/A} + + + + + ${%ago(h.getTimeSpanString(queuedResource.getQueuedTimestamp()))} + +
+
+ diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties new file mode 100644 index 000000000..6ceec1861 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties @@ -0,0 +1,46 @@ +# The MIT License +# +# Copyright 2023 Martin Pokorny. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +queue.isEmpty=The queue is currently empty. +queue.warning.count=The queue has {0} item(s). The oldest one was inserted {1} ago! +queue.warning.count.detail=\ +In many cases, users forget to un-reserve the resource (or an external API has died). \ +Sometimes the build does not release the resource. \ +This can happen when Jenkins crashes and the builds are no longer executable after restart.
\ +Please check the status and manually release the resource if necessary. +If you do not have permission to release the resource, contact your administrator. + +queue.table.column.request.type=Request type +queue.table.column.request.info=Request +queue.table.column.requested.by=Requested by +queue.table.column.requested.at=Requested at +queue.table.column.reason=Reason + +#status +resource.status.free=FREE +resource.status.locked=LOCKED by {1} +resource.status.reservedBy=RESERVED by {0} +resource.status.queuedBy=QUEUED by {0} {1} +ago={0} ago +label.requiredNumber={0} label(s) are required. +label.requiredAll=All possible labels are required. +label.status=Found {1} free resource(s) from {0} possible. \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly index 7bfc71e8e..9f67f9cbb 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly @@ -71,7 +71,7 @@ THE SOFTWARE.
- ${%ephemeral} + ${%resources.ephemeral}
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly new file mode 100644 index 000000000..1bee56b36 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly @@ -0,0 +1,79 @@ + + + + + + + + + + + ${%resource.status.reservedBy(resource.reservedBy)} + + + ${%resource.status.locked(rootURL + '/' + resource.build.url, resource.build.fullDisplayName)} + + + ${%resource.status.queuedBy(resource.queueItemProject, resource.queueItemId)} + + + + ${%resource.status.free} + + + + ${%ago(h.getTimeSpanString(resource.reservedTimestamp))} + + + + + + + + + ${%label.requiredNumber(queuedResource.requiredNumber)} + + + ${%label.requiredAll} + + + ${%label.status(it.getFreeResourceAmount(queuedResource.label), it.getAssignedResourceAmount(queuedResource.label))} + + + + + + ${%groovy.status} + + + + + ${%N/A} + + + + diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties new file mode 100644 index 000000000..75d4211e2 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties @@ -0,0 +1,34 @@ +# The MIT License +# +# Copyright 2023 Martin Pokorny. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +resource.status.locked=Locked by {1} +resource.status.reservedBy=Reserved by {0} +resource.status.queuedBy=Queued by {0} {1} +resource.status.free=Free + +label.requiredNumber=Requested {0} label(s). +label.requiredAll=Requested ALL possible labels. +label.status=
There are {1} resource(s) matched, but only {0} free. + +groovy.status=!!!Groovy expression is currently not supported!!! + +ago={0} ago \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly new file mode 100644 index 000000000..17f4b1d93 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly @@ -0,0 +1,75 @@ + + + + + + + + +
+
+
+ ${resource.name} +
+
+ + ${%resources.ephemeral} + +
+
+ +
+
+ ${resource.description} +
+
+
+
+
+
+ + + + + ${queuedResource.label} + + + + + + + + ${%groovy.code} + + + + + ${%N/A} + + +
+
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties new file mode 100644 index 000000000..f4de898e7 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright 2023 Martin Pokorny. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +resources.ephemeral=Ephemeral + +groovy.code=!!!Groovy expression is currently not supported!!! \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly new file mode 100644 index 000000000..022ae5151 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly @@ -0,0 +1,47 @@ + + + + + + + ${%type.resources} + + + + ${%type.label} + + + + + ${%type.groovy} + + + + ${%N/A} + + + diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties new file mode 100644 index 000000000..79cc4f277 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright 2023 Martin Pokorny. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +type.resources=Resources +type.label=Label +type.groovy=Groovy expression \ No newline at end of file From 4002ee23c67196d9d072ef20fe61830f883d5a1d Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:32:50 +0100 Subject: [PATCH 0818/1078] Inform user when resource-action was performed (#456) --- src/main/webapp/js/lockable-resources.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/js/lockable-resources.js b/src/main/webapp/js/lockable-resources.js index bfb03ee5f..9474f0434 100644 --- a/src/main/webapp/js/lockable-resources.js +++ b/src/main/webapp/js/lockable-resources.js @@ -10,11 +10,13 @@ function find_resource_name(element) { function resource_action(button, action) { // TODO: Migrate to form:link after Jenkins 2.233 (for button-styled links) var form = document.createElement('form'); + var resourceName = find_resource_name(button); form.setAttribute('method', 'POST'); - form.setAttribute('action', action + "?resource=" + encodeURIComponent(find_resource_name(button))); + form.setAttribute('action', action + "?resource=" + encodeURIComponent(resourceName)); crumb.appendToForm(form); document.body.appendChild(form); form.submit(); + notificationBar.show(action + ' was successfully performed on ' + resourceName, notificationBar.SUCCESS); } function replaceNote(element, resourceName) { From 891af28756d6c9e7388430ea87e01d06dea55a28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 21:17:14 +0000 Subject: [PATCH 0819/1078] Bump bom-2.361.x from 1798.vc671fe94856f to 1834.vc26f653a_a_b_10 (#458) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0e56180b0..78d505474 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1798.vc671fe94856f + 1834.vc26f653a_a_b_10 import pom From 3c9eee780e95392498c3583f63c603b23e79d6eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 21:37:15 +0000 Subject: [PATCH 0820/1078] Bump git-changelist-maven-extension from 1.4 to 1.5 (#459) --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 9ac2968bc..cb2841d90 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.4 + 1.5 From 9a36f48b87ed04e640afbcd27a1c76ac6d9577d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:06:11 +0000 Subject: [PATCH 0821/1078] Bump plugin from 4.54 to 4.55 (#465) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 78d505474..25add2658 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.54 + 4.55 From 3cd12dada1446a6d5afc49ea941071a162ae23a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:25:18 +0000 Subject: [PATCH 0822/1078] Bump git-changelist-maven-extension from 1.5 to 1.6 (#464) --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index cb2841d90..90787cbb2 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.5 + 1.6 From 11f0a52bf19756c1d01f5a2f3707e05c9ded7fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:43:51 +0000 Subject: [PATCH 0823/1078] Bump bom-2.361.x from 1834.vc26f653a_a_b_10 to 1836.vfe602c266c05 (#463) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 25add2658..0cbacbec4 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1834.vc26f653a_a_b_10 + 1836.vfe602c266c05 import pom From 91a9108f5b8b2e319e5e579476f1116c1d437fb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:08:23 +0000 Subject: [PATCH 0824/1078] Bump crowdin/github-action from 1.6.0 to 1.7.0 (#462) --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index f530e305e..52ff59307 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 - name: crowdin action - uses: crowdin/github-action@v1.6.0 + uses: crowdin/github-action@v1.7.0 with: upload_translations: false download_translations: true From ce12ba87eb97ba2390917386ea44bfecde949f22 Mon Sep 17 00:00:00 2001 From: Callum Moffat Date: Fri, 3 Mar 2023 10:58:04 -0500 Subject: [PATCH 0825/1078] Don't modify the candidates cache contents (#468) Fix an issue where resource would not be locked upon becoming free when using a label and quantity=0. --- .../LockableResourcesManager.java | 8 +--- .../FreeStyleProjectTest.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 262f1115a..c7b48b990 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -293,13 +293,7 @@ public synchronized boolean uncacheIfFreeing(LockableResource candidate, boolean Long queueItemId = entry.getKey(); List candidates = entry.getValue(); if (candidates != null && (candidates.size() == 0 || candidates.contains(candidate))) { - if (candidates.size() < 2) { - // Nothing is there, or would be after removing the one entry - cachedCandidates.invalidate(queueItemId); - } else { - // Reduce the referenced list - candidates.remove(candidate); - } + cachedCandidates.invalidate(queueItemId); } } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java index 3a21d1fc6..c5100d58b 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import jenkins.model.Jenkins; import org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction; @@ -227,6 +228,51 @@ public void autoCreateResource() throws IOException, InterruptedException, Execu assertNull(LockableResourcesManager.get().fromName("resource1")); } + @Test + public void competingLabelLocks() throws IOException, InterruptedException, ExecutionException { + LockableResourcesManager.get().createResourceWithLabel("resource1", "group1"); + LockableResourcesManager.get().createResourceWithLabel("resource2", "group2"); + LockableResourcesManager.get().createResource("shared"); + LockableResource shared = LockableResourcesManager.get().fromName("shared"); + shared.setEphemeral(false); + shared.getLabelsAsList().addAll(List.of("group1", "group2")); + FreeStyleProject f0 = j.createFreeStyleProject("f0"); + final Semaphore semaphore = new Semaphore(1); + f0.addProperty(new RequiredResourcesProperty("shared", null, null, null, null)); + f0.getBuildersList() + .add( + new TestBuilder() { + @Override + public boolean perform( + AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException { + semaphore.acquire(); + return true; + } + }); + FreeStyleProject f1 = j.createFreeStyleProject("f1"); + f1.addProperty(new RequiredResourcesProperty(null, null, "0", "group1", null)); + FreeStyleProject f2 = j.createFreeStyleProject("f2"); + f2.addProperty(new RequiredResourcesProperty(null, null, "0", "group2", null)); + + + semaphore.acquire(); + FreeStyleBuild fb0 = f0.scheduleBuild2(0).waitForStart(); + j.waitForMessage("acquired lock on [shared]", fb0); + QueueTaskFuture fb1q = f1.scheduleBuild2(0); + QueueTaskFuture fb2q = f2.scheduleBuild2(0); + + semaphore.release(); + j.waitForCompletion(fb0); + // fb1 or fb2 might run first, it shouldn't matter as long as they both get the resource + FreeStyleBuild fb1 = fb1q.waitForStart(); + FreeStyleBuild fb2 = fb2q.waitForStart(); + j.waitForMessage("acquired lock on [resource1, shared]", fb1); + j.waitForCompletion(fb1); + j.waitForMessage("acquired lock on [resource2, shared]", fb2); + j.waitForCompletion(fb2); + } + public static class PrinterBuilder extends TestBuilder { @Override From b7c3d377e72375afa2f5804ecad51ec231773420 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 20:29:25 +0000 Subject: [PATCH 0826/1078] Bump bom-2.361.x from 1836.vfe602c266c05 to 1887.vda_d0ddb_c15c4 (#469) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0cbacbec4..64e4cbc24 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1836.vfe602c266c05 + 1887.vda_d0ddb_c15c4 import pom From d07b8c8bb5d2b7ef98080517f7b47789019bed09 Mon Sep 17 00:00:00 2001 From: Pokorny Martin Date: Thu, 9 Mar 2023 23:07:53 +0100 Subject: [PATCH 0827/1078] Add column index to show resources in the same order as in Jenkins Management defined --- .../tableResources/table.jelly | 10 +++++++++- .../tableResources/table.properties | 1 + .../tableResources/table_cs.properties | 1 + .../tableResources/table_de.properties | 1 + .../tableResources/table_fr.properties | 1 + .../tableResources/table_sk.properties | 1 + 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly index 9f67f9cbb..7c188988b 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly @@ -37,9 +37,11 @@ THE SOFTWARE. + + @@ -52,6 +54,7 @@ THE SOFTWARE. + @@ -61,6 +64,11 @@ THE SOFTWARE. + + + diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.properties index d321370dd..15c31dc5b 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.properties @@ -21,6 +21,7 @@ # THE SOFTWARE. #table resources +resources.table.column.index=Index resources.table.column.resource=Resource resources.table.column.status=Status resources.table.column.labels=Labels diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_cs.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_cs.properties index dbfc8233f..b56b1b718 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_cs.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_cs.properties @@ -21,6 +21,7 @@ # THE SOFTWARE. #table resources +resources.table.column.index=Index resources.table.column.resource=Zdroj resources.table.column.status=Stav resources.table.column.labels=Popisky diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_de.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_de.properties index fc48b94b7..50d7dfe78 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_de.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_de.properties @@ -21,6 +21,7 @@ # THE SOFTWARE. #table resources +resources.table.column.index=Index resources.table.column.resource=Ressource resources.table.column.status=Status resources.table.column.labels=Labels diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_fr.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_fr.properties index 480bc471e..317a79500 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_fr.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_fr.properties @@ -21,6 +21,7 @@ # THE SOFTWARE. #table resources +resources.table.column.index=Index resources.table.column.resource=Ressource resources.table.column.status=Statut resources.table.column.labels=Libell\u00e9s diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_sk.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_sk.properties index 3d11e6300..3658d9758 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_sk.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table_sk.properties @@ -21,6 +21,7 @@ # THE SOFTWARE. #table resources +resources.table.column.index=Index resources.table.column.resource=Zdroj resources.table.column.status=Stav resources.table.column.labels=\u0160t\u00edtky From 0ce2e3027cf43c1cb68043996b38e2c761f0cb01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:42:57 +0000 Subject: [PATCH 0828/1078] Bump crowdin/github-action from 1.7.0 to 1.7.1 (#472) --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 52ff59307..226c80353 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 - name: crowdin action - uses: crowdin/github-action@v1.7.0 + uses: crowdin/github-action@v1.7.1 with: upload_translations: false download_translations: true From 1da3e4dc4502b0073a1ab4827cde1b88811129df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:01:09 +0000 Subject: [PATCH 0829/1078] Bump plugin from 4.55 to 4.56 (#471) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 64e4cbc24..8732bfc06 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.55 + 4.56 From 3010e3e0883c6109c1fede77d3a3e47e788fe958 Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Thu, 23 Mar 2023 14:15:25 -0600 Subject: [PATCH 0830/1078] Fix broken documentation links (#473) Fixes https://github.com/jenkins-infra/jenkins.io/issues/6186 by using the correct spelling of the word "pipeline" in the link. Thanks to https://github.com/jjmastro for reporting the issue through the Jenkins documentation site. --- .../jenkins/plugins/lockableresources/LockStep/help-label.html | 2 +- .../plugins/lockableresources/LockStep/help-variable.html | 2 +- .../plugins/lockableresources/LockStepResource/help-label.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-label.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-label.html index c4c5de1eb..d89e6a47c 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-label.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-label.html @@ -8,7 +8,7 @@

See also examples and - Scripted vs declarative pipeline + Scripted vs declarative pipeline .

diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html index 67da6cc50..9ff45eae6 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStep/help-variable.html @@ -5,7 +5,7 @@

See also examples and - Scripted vs declarative pipeline + Scripted vs declarative pipeline .

diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-label.html b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-label.html index c4c5de1eb..d89e6a47c 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-label.html +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockStepResource/help-label.html @@ -8,7 +8,7 @@

See also examples and - Scripted vs declarative pipeline + Scripted vs declarative pipeline .

From b9f6b0553effbba6098699ea540c5f77ece7dea4 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Mon, 27 Mar 2023 13:25:58 +0200 Subject: [PATCH 0831/1078] Allow to use Jenkins label parser to allocate lockable-resources in more sophisticated way (#475) * Use jenkins labels parser * increase Jenkins version to make Java compiler happy * make jenkins file happy * extend tests getAssignedResourceAmount to cover missing lines * make isValidLabel more robust * example * isValidLabel * getResourcesWithLabel * spotbugs * Update README.md Co-authored-by: Jan-Frederik Schmidt * update docu --------- Co-authored-by: Jan-Frederik Schmidt --- Jenkinsfile | 6 ++--- README.md | 19 +++++++++++++++ pom.xml | 2 +- .../lockableresources/LockableResource.java | 22 ++++++++++++++++- .../LockableResourcesManager.java | 24 +++++++++++++++++-- .../LockableResourcesRootActionTest.java | 7 ++++++ 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 964cdb4ce..79233bce0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,10 +4,10 @@ */ buildPlugin(useContainerAgent: true, configurations: [ // Test the common case (i.e., a recent LTS release) on both Linux and Windows. - [ platform: 'linux', jdk: '11', jenkins: '2.361.4' ], - [ platform: 'windows', jdk: '11', jenkins: '2.361.4' ], + [ platform: 'linux', jdk: '11' ], + [ platform: 'windows', jdk: '11'], // Test the bleeding edge of the compatibility spectrum (i.e., the latest supported Java runtime). // see also https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ - [ platform: 'linux', jdk: '17', jenkins: '2.361.4' ], + [ platform: 'linux', jdk: '17', jenkins: '2.387.1' ], ]) diff --git a/README.md b/README.md index cf99d4039..ca54ea0bb 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,24 @@ Detailed documentation can be found as part of the [Pipeline Steps](https://jenkins.io/doc/pipeline/steps/lockable-resources/) documentation. +### Jenkins label parser allows sophisticated filtering + +The plugin uses the Jenkins-internal label parser for filtering lockable resources. A full list of supported operators and syntax examples can be found in the [official documentation](https://www.jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#node-allocate-node). + +```groovy +lock(label: 'labelA && labelB', variable : 'someVar') { + echo 'labelA && labelB acquired by: ' + env.someVar; +} + +lock(label: 'labelA || labelB', variable : 'someVar') { + echo 'labelA || labelB acquired by: ' + env.someVar; +} + +lock(label: 'labelA || labelB || labelC', variable : 'someVar', quantity : 100) { + echo 'labelA || labelB || labelC acquired by: ' + env.someVar; +} +``` + #### Multiple resource lock ```groovy @@ -162,6 +180,7 @@ echo 'Finish' More examples are [here](src/doc/examples/readme.md). ---- + ## Configuration as Code This plugin can be configured via diff --git a/pom.xml b/pom.xml index 8732bfc06..4c79a220e 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 999999-SNAPSHOT - 2.361.4 + 2.387.1 jenkinsci/${project.artifactId}-plugin Max Low diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 5ab0a40ee..9b4c026e5 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -20,19 +20,23 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; +import hudson.model.Label; import hudson.model.Queue; import hudson.model.Queue.Item; import hudson.model.Queue.Task; import hudson.model.Run; import hudson.model.User; +import hudson.model.labels.LabelAtom; import hudson.tasks.Mailer.UserProperty; import java.io.Serializable; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; @@ -236,10 +240,26 @@ public boolean hasLabel(String labelToFind) { return this.labelsContain(labelToFind); } + //---------------------------------------------------------------------------- public boolean isValidLabel(String candidate, Map params) { - return labelsContain(candidate); + if (candidate == null || candidate.isEmpty()) { + return false; + } + + if (labelsContain(candidate)) { + return true; + } + + final Label labelExpression = Label.parseExpression(candidate); + Set atomLabels = new HashSet<>(); + for(String label : this.getLabelsAsList()) { + atomLabels.add(new LabelAtom(label)); + } + + return labelExpression.matches(atomLabels); } + //---------------------------------------------------------------------------- /** * Checks if the resource contain label *candidate*. * @param candidate Labels to find. diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index c7b48b990..cd2116c40 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -143,10 +143,27 @@ public List getResourcesFromBuild(Run build) { return matching; } - public Boolean isValidLabel(String label) { - return this.getAllLabels().contains(label); + //---------------------------------------------------------------------------- + @SuppressFBWarnings(value = "NP_LOAD_OF_KNOWN_NULL_VALUE", + justification = "null value is checked correctly") + public Boolean isValidLabel(@Nullable String label) { + if (label == null || label.isEmpty()) { + return false; + } + if (this.getAllLabels().contains(label)) + return true; + + final Map params = null; + for (LockableResource r : this.resources) { + if (r.isValidLabel(label, params)) { + return true; + } + } + + return false; } + //---------------------------------------------------------------------------- public Set getAllLabels() { Set labels = new HashSet<>(); for (LockableResource r : this.resources) { @@ -174,6 +191,9 @@ public int getFreeResourceAmount(String label) { public List getResourcesWithLabel(String label, Map params) { List found = new ArrayList<>(); + if (label == null || label.isEmpty()) { + return found; + } for (LockableResource r : this.resources) { if (r.isValidLabel(label, params)) found.add(r); } diff --git a/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java b/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java index 0f7d2d267..32393d79f 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootActionTest.java @@ -412,6 +412,13 @@ public void testGetAssignedResourceAmount() throws IOException, ServletException assertEquals("initial check", 2, action.getAssignedResourceAmount("resource-label-2")); assertEquals("initial check", 1, action.getAssignedResourceAmount("resource-label-3")); + // check label parsing + assertEquals("check after reservation", 3, action.getAssignedResourceAmount("resource-label-1")); + assertEquals("check after reservation", 1, action.getAssignedResourceAmount("resource-label-1 && resource-label-2 && resource-label-3")); + assertEquals("check after reservation", 2, action.getAssignedResourceAmount("resource-label-1 && resource-label-2")); + assertEquals("check after reservation", 2, action.getAssignedResourceAmount("resource-label-3 || resource-label-2")); + + // reserve one resource. Amount of assigned labels should change when(req.getParameter("resource")).thenReturn("resource-A"); action.doReserve(req, rsp); From 2e4441f0a254763ffc759e7cef46aa30083f5f4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:13:18 +0000 Subject: [PATCH 0832/1078] Bump plugin from 4.56 to 4.57 (#476) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4c79a220e..bb09972d4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.56 + 4.57 From 59a5fbf8a27b17c4aa4a062323241399a3caa9ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:27:31 +0000 Subject: [PATCH 0833/1078] Bump bom-2.361.x from 1887.vda_d0ddb_c15c4 to 1948.veb_1fd345d3a_e (#477) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bb09972d4..de32e2728 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1887.vda_d0ddb_c15c4 + 1948.veb_1fd345d3a_e import pom From 8fad6d8bacecfe21735a22afb56f373be6a463c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:25:03 +0000 Subject: [PATCH 0834/1078] Bump bom-2.361.x from 1948.veb_1fd345d3a_e to 1968.vb_14a_29e76128 (#479) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index de32e2728..5576a693b 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1948.veb_1fd345d3a_e + 1968.vb_14a_29e76128 import pom From 7c5f8f31d2ee451cde65f100c325166a8f2aee31 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:48:10 +0200 Subject: [PATCH 0835/1078] Remember search text in tables (#474) --- .../tableLabels/table.jelly | 1 + .../tableQueue/table.jelly | 1 + .../tableResources/table.jelly | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table.jelly index b6a72e7bf..852900b6b 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableLabels/table.jelly @@ -31,6 +31,7 @@ THE SOFTWARE. class="jenkins-table jenkins-!-margin-bottom-4 data-table" id="lockable-resources-labels" isLoaded="true" + data-remember-search-text="true" data-columns-definition="[null, null, null, null]" data-table-configuration="{}" > diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.jelly index 43e06295c..e3ccbe4ee 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.jelly @@ -50,6 +50,7 @@ THE SOFTWARE. class="jenkins-table jenkins-!-margin-bottom-4 data-table" id="lockable-resources-queue" isLoaded="true" + data-remember-search-text="true" data-columns-definition="[null, null, null, null, null]" data-table-configuration="{}" > diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly index 7c188988b..c68d08565 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly @@ -34,11 +34,14 @@ THE SOFTWARE.
-
${%resources.table.column.index} ${%resources.table.column.resource} ${%resources.table.column.status} ${%resources.table.column.timestamp}
${i + 1}
+
From c0d7ed96a19129d29474c73c41d316adcfa6209f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:07:32 +0000 Subject: [PATCH 0836/1078] Bump plugin from 4.57 to 4.58 (#480) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5576a693b..02e956a34 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.57 + 4.58 From 93b87bab41635e1174b33f676a2394be45d724fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:11:15 +0000 Subject: [PATCH 0837/1078] Bump bom-2.361.x from 1968.vb_14a_29e76128 to 1981.v17df70e84a_a_1 (#481) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 02e956a34..d43051c14 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1968.vb_14a_29e76128 + 1981.v17df70e84a_a_1 import pom From 287ae5c54faeef81be24887f6fd1b8ce9dfe4042 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:26:37 +0000 Subject: [PATCH 0838/1078] Bump plugin from 4.58 to 4.59 (#482) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d43051c14..6d896074a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.58 + 4.59 From c38b9bdd5e46a73b0183110e7e020823c6e3b945 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 05:19:07 +0000 Subject: [PATCH 0839/1078] Bump bom-2.361.x from 1981.v17df70e84a_a_1 to 2000.v4677a_6e0ffea (#487) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6d896074a..a501fd8f5 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 1981.v17df70e84a_a_1 + 2000.v4677a_6e0ffea import pom From 25b75fe6b40240346fb8096a431b79f5dcc03734 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Tue, 18 Apr 2023 17:39:34 -0700 Subject: [PATCH 0840/1078] Upgrade plugin parent POM from 4.59 to 4.60 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a501fd8f5..163cf435a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.59 + 4.60 @@ -148,7 +148,7 @@ org.mockito - mockito-inline + mockito-core test From b6d6a7fd98815fe029e03f6ceae9b4bccc6ff9bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:15:58 +0000 Subject: [PATCH 0841/1078] Bump plugin from 4.60 to 4.61 (#491) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 163cf435a..120564908 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.60 + 4.61 From b67f58c1235bc325cc55a807fcf4f880a58b32b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:33:18 +0000 Subject: [PATCH 0842/1078] Bump bom-2.361.x from 2000.v4677a_6e0ffea to 2025.v816d28f1e04f (#490) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 120564908..84702312a 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ io.jenkins.tools.bom bom-2.361.x - 2000.v4677a_6e0ffea + 2025.v816d28f1e04f import pom From 59db2b994618695463f6274d5601b4af7cc8cff9 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:26:20 +0200 Subject: [PATCH 0843/1078] Enable Jenkins node (agent) mirroring into lockable-resource (#486) * Node mirroring * Update src/main/java/org/jenkins/plugins/lockableresources/nodes/NodesMirror.java Co-authored-by: Jan-Frederik Schmidt * PR review --------- Co-authored-by: Jan-Frederik Schmidt --- README.md | 22 +++++ .../BackwardCompatibility.java | 2 +- .../lockableresources/LockableResource.java | 15 +++ .../LockableResourcesManager.java | 2 +- .../lockableresources/nodes/NodesMirror.java | 99 +++++++++++++++++++ .../lockableresources/util/Constants.java | 6 ++ .../lockableresources/NodesMirrorTest.java | 83 ++++++++++++++++ 7 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/jenkins/plugins/lockableresources/nodes/NodesMirror.java create mode 100644 src/main/java/org/jenkins/plugins/lockableresources/util/Constants.java create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java diff --git a/README.md b/README.md index ca54ea0bb..8f50db6d2 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,28 @@ More examples are [here](src/doc/examples/readme.md). ---- +## Node mirroring + +Lockable resources plugin allow to mirror nodes (agents) into lockable resources. This eliminate effort by re-creating resources on every node change. + +That means when you create new node, it will be also created new lockable-resource with the same name. When the node has been deleted, lockable-resource will be deleted too. + +Following properties are mirrored: + +- name. +- labels. Please note, that labels still contains node-name self. +- description. + +To allow this behavior start jenkins with option `-Dorg.jenkins.plugins.lockableresources.ENABLE_NODE_MIRROR=true` or run this groovy code. + +```groovy +System.setProperty("org.jenkins.plugins.lockableresources.ENABLE_NODE_MIRROR", "true"); +``` + +note: When the node has been deleted, during the lockable-resource is locked / reserved / queued, then the lockable-resource will be NOT deleted. + +---- + ## Configuration as Code This plugin can be configured via diff --git a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java index 0a6abe87f..e7a3d6013 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/BackwardCompatibility.java @@ -34,7 +34,7 @@ private BackwardCompatibility() {} @Initializer(after = InitMilestone.JOB_LOADED) public static void compatibilityMigration() { List resources = LockableResourcesManager.get().getResources(); - LOG.log(Level.FINE, "lockable-resource-plugin compatibility migration task run for " + resources.size() + " resources"); + LOG.log(Level.FINE, "lockable-resources-plugin compatibility migration task run for " + resources.size() + " resources"); for (LockableResource resource : resources) { List queuedContexts = resource.getQueuedContexts(); if (!queuedContexts.isEmpty()) { diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 9b4c026e5..5a67edd86 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -100,6 +100,8 @@ public class LockableResource extends AbstractDescribableImpl private static final long serialVersionUID = 1L; + private transient boolean isNode = false; + /** * Was used within the initial implementation of Pipeline functionality using {@link LockStep}, * but became deprecated once several resources could be locked at once. See queuedContexts in @@ -154,6 +156,14 @@ public List getQueuedContexts() { return this.queuedContexts; } + public boolean isNodeResource() { + return isNode; + } + + public void setNodeResource(boolean b) { + isNode = b; + } + @Exported public String getName() { return name; @@ -323,6 +333,11 @@ public String getReservedBy() { return reservedBy; } + /** Return true when resource is free. False otherwise*/ + public boolean isFree() { + return (!this.isLocked() && !this.isReserved() && !this.isQueued()); + } + @Exported public boolean isReserved() { return reservedBy != null; diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index cd2116c40..1b263cdf5 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -74,7 +74,7 @@ public List getResources() { public synchronized List getDeclaredResources() { ArrayList declaredResources = new ArrayList<>(); for (LockableResource r : resources) { - if (!r.isEphemeral()) { + if (!r.isEphemeral() && !r.isNodeResource()) { declaredResources.add(r); } } diff --git a/src/main/java/org/jenkins/plugins/lockableresources/nodes/NodesMirror.java b/src/main/java/org/jenkins/plugins/lockableresources/nodes/NodesMirror.java new file mode 100644 index 000000000..4931fb7b4 --- /dev/null +++ b/src/main/java/org/jenkins/plugins/lockableresources/nodes/NodesMirror.java @@ -0,0 +1,99 @@ + + +package org.jenkins.plugins.lockableresources; + + +import hudson.init.InitMilestone; +import hudson.init.Initializer; +import hudson.Extension; +import hudson.model.Node; +import hudson.slaves.ComputerListener; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import jenkins.model.Jenkins; +import jenkins.util.SystemProperties; +import org.jenkins.plugins.lockableresources.util.Constants; + +//----------------------------------------------------------------------------- +/** Mirror Jenkins nodes to lockable-resources +*/ +@Extension +public class NodesMirror extends ComputerListener { + + private static final Logger LOG = Logger.getLogger(NodesMirror.class.getName()); + + //--------------------------------------------------------------------------- + private static boolean isNodeMirrorEnabled() { + return SystemProperties.getBoolean(Constants.SYSTEM_PROPERTY_ENABLE_NODE_MIRROR); + } + + //--------------------------------------------------------------------------- + @Initializer(after = InitMilestone.JOB_LOADED) + public static void createNodeResources() { + LOG.log(Level.FINE, "lockable-resources-plugin configure node resources"); + mirrorNodes(); + } + + //--------------------------------------------------------------------------- + @Override + public final void onConfigurationChange() { + mirrorNodes(); + } + + //--------------------------------------------------------------------------- + private static void mirrorNodes() { + if (!isNodeMirrorEnabled()) { + return; + } + + deleteExistingNodes(); + + for (Node n : Jenkins.get().getNodes()) { + mirrorNode(n); + } + } + + //--------------------------------------------------------------------------- + private static void deleteExistingNodes() { + LockableResourcesManager lrm = LockableResourcesManager.get(); + Iterator resourceIterator = lrm.getResources().iterator(); + while (resourceIterator.hasNext()) { + LockableResource resource = resourceIterator.next(); + if (!resource.isNodeResource()) { + continue; + } + if (resource.isFree()) { + // we can remove this resource. Is newer used currently + resourceIterator.remove(); + } else { + LOG.log(Level.FINE, "lockable-resources-plugin skip node deletion of: " + resource.getName() + ". Reason: Currently locked"); + } + } + } + + //--------------------------------------------------------------------------- + private static void mirrorNode(Node node) { + if (node == null) { + return; + } + + LockableResourcesManager lrm = LockableResourcesManager.get(); + LockableResource nodeResource = lrm.fromName(node.getNodeName()); + boolean exist = nodeResource != null; + if (!exist) { + nodeResource = new LockableResource(node.getNodeName()); + } + nodeResource.setLabels(node.getAssignedLabels().stream().map(Object::toString).collect(Collectors.joining(" "))); + nodeResource.setNodeResource(true); + nodeResource.setEphemeral(false); + nodeResource.setDescription(node.getNodeDescription()); + LOG.log(Level.FINE, "lockable-resources-plugin add node-resource: " + nodeResource.getName()); + if (!exist) { + lrm.getResources().add(nodeResource); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkins/plugins/lockableresources/util/Constants.java b/src/main/java/org/jenkins/plugins/lockableresources/util/Constants.java new file mode 100644 index 000000000..b10e915b7 --- /dev/null +++ b/src/main/java/org/jenkins/plugins/lockableresources/util/Constants.java @@ -0,0 +1,6 @@ + +package org.jenkins.plugins.lockableresources.util; + +public class Constants { + public static final String SYSTEM_PROPERTY_ENABLE_NODE_MIRROR = "org.jenkins.plugins.lockableresources.ENABLE_NODE_MIRROR"; +} \ No newline at end of file diff --git a/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java b/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java new file mode 100644 index 000000000..60f86d423 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java @@ -0,0 +1,83 @@ +package org.jenkins.plugins.lockableresources; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.jenkins.plugins.lockableresources.util.Constants; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class NodesMirrorTest { + + @Rule public final JenkinsRule j = new JenkinsRule(); + + @Test + public void mirror_few_nodes() throws Exception { + System.setProperty(Constants.SYSTEM_PROPERTY_ENABLE_NODE_MIRROR, "true"); + + j.createSlave("FirstAgent", "label label2", null); + j.createSlave("SecondAgent", null, null); + + // this is asynchronous operation, so wait until resources are created. + for(int i = 1; LockableResourcesManager.get().fromName("SecondAgent") != null && i <= 10; i++) { + Thread.sleep(100); + } + + LockableResource firstAgent = LockableResourcesManager.get().fromName("FirstAgent"); + + assertEquals("FirstAgent", firstAgent.getName()); + // ! jenkins add always the node name as a label + assertEquals("FirstAgent label label2", firstAgent.getLabels()); + + LockableResource secondAgent = LockableResourcesManager.get().fromName("SecondAgent"); + assertEquals("SecondAgent", secondAgent.getName()); + assertEquals("SecondAgent", secondAgent.getLabels()); + + // delete agent + j.jenkins.removeNode(j.jenkins.getNode("FirstAgent")); + + for(int i = 1; LockableResourcesManager.get().fromName("FirstAgent") == null && i <= 10; i++) { + Thread.sleep(100); + } + assertNull(LockableResourcesManager.get().fromName("FirstAgent")); + assertNotNull(LockableResourcesManager.get().fromName("SecondAgent")); + } + + @Test + public void mirror_locked_nodes() throws Exception { + System.setProperty("org.jenkins.plugins.lockableresources.ENABLE_NODE_MIRROR", "true"); + + j.createSlave("FirstAgent", "label label2", null); + // this is asynchronous operation, so wait until resources has been created. + for(int i = 1; LockableResourcesManager.get().fromName("FirstAgent") != null && i <= 10; i++) { + Thread.sleep(100); + } + assertNotNull(LockableResourcesManager.get().fromName("FirstAgent")); + + WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "lock(label: 'label && label2', variable : 'lockedNode') {\n" + + " echo 'wait for node: ' + env.lockedNode\n" + + " semaphore 'wait-inside'\n" + + "}\n" + + "echo 'Finish'", + true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForMessage("wait for node: FirstAgent", b1); + SemaphoreStep.waitForStart("wait-inside/1", b1); + j.jenkins.removeNode(j.jenkins.getNode("FirstAgent")); + SemaphoreStep.success("wait-inside/1", null); + // this resource is not removed, because it was locked. + Thread.sleep(1000); + assertNotNull(LockableResourcesManager.get().fromName("FirstAgent")); + } +} From 6322329cdad58d1184d08b2cc7b4e0229b475af0 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sat, 29 Apr 2023 13:56:02 +0200 Subject: [PATCH 0844/1078] Tests for declarative pipeline (#492) --- pom.xml | 5 + .../DeclarativePipelineTest.java | 139 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java diff --git a/pom.xml b/pom.xml index 84702312a..77954ba18 100644 --- a/pom.xml +++ b/pom.xml @@ -136,6 +136,11 @@ workflow-job test + + org.jenkinsci.plugins + pipeline-model-definition + test + io.jenkins configuration-as-code diff --git a/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java b/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java new file mode 100644 index 000000000..e6c313883 --- /dev/null +++ b/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java @@ -0,0 +1,139 @@ +package org.jenkins.plugins.lockableresources; + +import com.google.common.base.Joiner; +import hudson.model.Result; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import static org.junit.Assert.assertNull; + +public class DeclarativePipelineTest { + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Test + public void lockByIdInOptionsSection() throws Exception { + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition(m("pipeline {", + " agent none", + " options {", + " lock resource: 'resource1'", + " }", + " stages {", + " stage('test') {", + " steps {", + " echo 'foo'", + " }", + " }", + " }", + "}"), true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Resource [resource1] did not exist. Created.", b1); + assertNull(LockableResourcesManager.get().fromName("resource1")); + } + + @Test + public void lockByLabelInOptionsSection() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition(m("pipeline {", + " agent none", + " options {", + " lock label: 'label1', resource : null", + " }", + " stages {", + " stage('test') {", + " steps {", + " echo 'foo'", + " }", + " }", + " }", + "}"), true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Lock acquired on [Label: label1]", b1); + } + + @Test + public void stepScriptLockByLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition(m("pipeline {", + " agent none", + " stages {", + " stage('test') {", + " steps {", + " script {", + " lock(label: 'label1', resource : null, variable: 'LABEL_LOCKED', quantity: 1) {", + " echo \"Lock acquired: ${LABEL_LOCKED}\"", + " }", + " }", + " }", + " }", + " }", + "}"), true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Lock acquired: resource1", b1); + } + + @Test + public void stepLockByLabel() throws Exception { + LockableResourcesManager.get().createResourceWithLabel("resource1", "label1"); + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition(m("pipeline {", + " agent none", + " stages {", + " stage('test') {", + " steps {", + " lock(label: 'label1', resource : null, variable: 'LABEL_LOCKED', quantity: 1) {", + " echo \"Lock acquired: ${LABEL_LOCKED}\"", + " }", + " }", + " }", + " }", + "}"), true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.SUCCESS, b1); + j.assertLogContains("Lock acquired: resource1", b1); + } + + @Test + public void missingLabel() throws Exception { + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition(m("pipeline {", + " agent none", + " stages {", + " stage('test') {", + " steps {", + " lock() {", + " echo \"This will still be executed\"", + " }", + " }", + " }", + " }", + "}"), true)); + WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); + j.waitForCompletion(b1); + j.assertBuildStatus(Result.FAILURE, b1); + j.assertLogContains("Missing required parameter: \"resource\"", b1); + } + + private String m(String... lines) { + return Joiner.on('\n').join(lines); + } +} \ No newline at end of file From 61f42a8a138483b240ccee8a5514db1419538099 Mon Sep 17 00:00:00 2001 From: Markus Winter Date: Mon, 1 May 2023 22:06:02 +0200 Subject: [PATCH 0845/1078] get bom version in sync with the jenkins version (#493) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 77954ba18..fd5c15ac7 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ io.jenkins.tools.bom - bom-2.361.x + bom-2.387.x 2025.v816d28f1e04f import pom From f5585067252989f247cc5d74379eeb44e3ccaa87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 20:29:33 +0000 Subject: [PATCH 0846/1078] Bump crowdin/github-action from 1.7.1 to 1.8.0 (#495) --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 226c80353..96e6ff58c 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 - name: crowdin action - uses: crowdin/github-action@v1.7.1 + uses: crowdin/github-action@v1.8.0 with: upload_translations: false download_translations: true From 5cbaf227763420e8c1452dd74014003d1152912b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 21:04:43 +0000 Subject: [PATCH 0847/1078] Bump plugin from 4.61 to 4.62 (#494) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fd5c15ac7..9f81d98e7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 4.61 + 4.62 From 9fa89cff25fd11747a164553bc49ae7f55ce7fa5 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Tue, 2 May 2023 11:46:43 +0200 Subject: [PATCH 0848/1078] Add user defined properties to lockable resource (#394) * Added UI to set properties on Lockable Resources * Document properties in the README.md * Expose the properties to environment variables * Removed unnecessary Copyright to 6WIND * Removed unnecessary Copyright to 6WIND * maintain lock ordering when reporting in environment variables Fixes https://github.com/jenkinsci/lockable-resources-plugin/issues/300 : The order of the locked resources in the environment variable does not match the order in the extra parameter * maintain lock ordering when reporting in environment variables Fixes https://github.com/jenkinsci/lockable-resources-plugin/issues/300 : The order of the locked resources in the environment variable does not match the order in the extra parameter * maintain lock ordering when reporting in environment variables Fixes https://github.com/jenkinsci/lockable-resources-plugin/issues/300 : The order of the locked resources in the environment variable does not match the order in the extra parameter * maintain lock ordering when reporting in environment variables Fixes https://github.com/jenkinsci/lockable-resources-plugin/issues/300 : The order of the locked resources in the environment variable does not match the order in the extra parameter * Revert "maintain lock ordering when reporting in environment variables" This reverts commit be88b857bf84b04c714ea71ea5883c9deaa259bd. * Revert "maintain lock ordering when reporting in environment variables" This reverts commit 82a77704859a3f50e9b9fbe8122cef1fe51f1105. * Revert "maintain lock ordering when reporting in environment variables" This reverts commit 1653c7b8939909d285bc3a12f6cbf927f1e1936a. * Revert "maintain lock ordering when reporting in environment variables" This reverts commit dfdfc5b996ecdb2d1ba31ca51b5010c9d8a05300. * Adding properties in a colum of the lock descriptions * and now fix it after master merge * style: Remove commented out line --------- Co-authored-by: Gaspard Petit Co-authored-by: Jan-Frederik Schmidt --- README.md | 9 +- .../lockableresources/LockStepExecution.java | 24 +++-- .../lockableresources/LockableResource.java | 11 +++ .../LockableResourceProperty.java | 58 ++++++++++++ .../LockableResourcesManager.java | 47 +++++++--- .../queue/LockRunListener.java | 88 ++++++++++--------- .../LockableResource/config.jelly | 9 ++ .../LockableResource/config.properties | 5 +- .../LockableResourceProperty/config.jelly | 10 +++ .../config.properties | 24 +++++ .../tableResources/table.jelly | 29 +++++- .../tableResources/table.properties | 4 + src/main/webapp/css/style.css | 10 +++ .../lockableresources/LockStepTest.java | 25 +++++- 14 files changed, 284 insertions(+), 69 deletions(-) create mode 100644 src/main/java/org/jenkins/plugins/lockableresources/LockableResourceProperty.java create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.jelly create mode 100644 src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.properties diff --git a/README.md b/README.md index 8f50db6d2..ac9c5a473 100644 --- a/README.md +++ b/README.md @@ -100,11 +100,12 @@ lock(resource: 'staging-server', inversePrecedence: true) { } ``` -#### Resolve a variable configured with the resource name +#### Resolve a variable configured with the resource name and properties ```groovy lock(label: 'some_resource', variable: 'LOCKED_RESOURCE') { echo env.LOCKED_RESOURCE + echo env.LOCKED_RESOURCE_PROP_ABC } ``` @@ -117,9 +118,11 @@ lock(label: 'some_resource', variable: 'LOCKED_RESOURCE', quantity: 2) { // first lock echo env.LOCKED_RESOURCE0 + echo env.LOCKED_RESOURCE0_PROP_ABC // second lock echo env.LOCKED_RESOURCE1 + echo env.LOCKED_RESOURCE1_PROP_ABC } ``` @@ -220,6 +223,10 @@ unclassified: reservedBy: "Reserved due maintenance window" - name: "S7_1200_2" labels: "plc:S7 model:1200" + - name: "Resource-with-properties" + properties: + - name: "Property-A" + value: "Value" ``` Properties *description*, *labels* and *reservedBy* are optional. diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index 2eeb01814..0f2814d79 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -9,8 +9,9 @@ import java.io.PrintStream; import java.io.Serializable; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map.Entry; import java.util.Locale; import java.util.Map; import java.util.logging.Level; @@ -111,7 +112,7 @@ public boolean start() throws Exception { @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "not sure which exceptions might be catch.") public static void proceed( - final List resourceNames, + final LinkedHashMap> lockedResources, StepContext context, String resourceDescription, final String variable, @@ -136,7 +137,7 @@ public static void proceed( BodyInvoker bodyInvoker = context .newBodyInvoker() - .withCallback(new Callback(resourceNames, resourceDescription, inversePrecedence)); + .withCallback(new Callback(new ArrayList<>(lockedResources.keySet()), resourceDescription, inversePrecedence)); if (variable != null && variable.length() > 0) { // set the variable for the duration of the block bodyInvoker.withContext( @@ -147,11 +148,18 @@ public static void proceed( @Override public void expand(@NonNull EnvVars env) { - final Map variables = new HashMap<>(); - final String resources = String.join(",", resourceNames); - variables.put(variable, resources); - for (int index = 0; index < resourceNames.size(); ++index) { - variables.put(variable + index, resourceNames.get(index)); + final LinkedHashMap variables = new LinkedHashMap<>(); + final String resourceNames = lockedResources.keySet().stream().collect(Collectors.joining(",")); + variables.put(variable, resourceNames); + int index = 0; + for (Entry> lockResourceEntry : lockedResources.entrySet()) { + String lockEnvName = variable + index; + variables.put(lockEnvName, lockResourceEntry.getKey()); + for (LockableResourceProperty lockProperty : lockResourceEntry.getValue()) { + String propEnvName = lockEnvName + "_" + lockProperty.getName(); + variables.put(propEnvName, lockProperty.getValue()); + } + ++index; } LOGGER.finest("Setting " + variables.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(", ")) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java index 5a67edd86..acb0aefe4 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResource.java @@ -90,6 +90,7 @@ public class LockableResource extends AbstractDescribableImpl * being held, it becomes ephemeral and will disappear when freed. */ private boolean ephemeral; + private List properties = new ArrayList<>(); private long queueItemId = NOT_QUEUED; private String queueItemProject = null; @@ -279,6 +280,16 @@ private boolean labelsContain(String candidate) { return this.getLabelsAsList().contains(candidate); } + @Exported + public List getProperties() { + return properties; + } + + @DataBoundSetter + public void setProperties(List properties) { + this.properties = (properties == null ? new ArrayList<>() : properties); + } + /** * Checks if the script matches the requirement. * diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourceProperty.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourceProperty.java new file mode 100644 index 000000000..5233542cd --- /dev/null +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourceProperty.java @@ -0,0 +1,58 @@ +package org.jenkins.plugins.lockableresources; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import java.io.Serializable; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.export.Exported; + +public class LockableResourceProperty extends AbstractDescribableImpl + implements Serializable { + + private String name; + private String value; + + @DataBoundConstructor + public LockableResourceProperty() { + } + + @DataBoundSetter + public void setName(String name) { + this.name = name; + } + + @DataBoundSetter + public void setValue(String value) { + this.value = value; + } + + @Exported + public String getName() { + return name; + } + + @Exported + public String getValue() { + return value; + } + + @Override + public String toString() { + return name; + } + + @Extension + public static class DescriptorImpl extends Descriptor { + + @NonNull + @Override + public String getDisplayName() { + return "Property"; + } + } + + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 1b263cdf5..298a5c1b6 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -26,7 +26,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import jenkins.model.GlobalConfiguration; import jenkins.model.Jenkins; import net.sf.json.JSONObject; @@ -457,10 +458,10 @@ public synchronized boolean lock( } if (context != null) { // since LockableResource contains transient variables, they cannot be correctly serialized - // hence we use their unique resource names - List resourceNames = new ArrayList<>(); + // hence we use their unique resource names and properties + LinkedHashMap> resourceNames = new LinkedHashMap<>(); for (LockableResource resource : resources) { - resourceNames.add(resource.getName()); + resourceNames.put(resource.getName(), resource.getProperties()); } LockStepExecution.proceed(resourceNames, context, logmessage, variable, inversePrecedence); } @@ -571,13 +572,13 @@ public synchronized void unlockNames( // remove context from queue and process it unqueueContext(nextContext.getContext()); - List resourceNamesToLock = new ArrayList<>(); + LinkedHashMap> resourcesToLock = new LinkedHashMap<>(); // lock all (old and new resources) for (LockableResource requiredResource : requiredResourceForNextContext) { try { requiredResource.setBuild(nextContext.getContext().get(Run.class)); - resourceNamesToLock.add(requiredResource.getName()); + resourcesToLock.put(requiredResource.getName(), requiredResource.getProperties()); } catch (Exception e) { // skip this context, as the build cannot be retrieved (maybe it was deleted while // running?) @@ -616,7 +617,7 @@ public synchronized void unlockNames( // continue with next context LockStepExecution.proceed( - resourceNamesToLock, + resourcesToLock, nextContext.getContext(), nextContext.getResourceDescription(), nextContext.getVariableName(), @@ -743,6 +744,28 @@ public synchronized boolean createResourceWithLabel(String name, String label) { return false; } + @Restricted(NoExternalUse.class) + public synchronized boolean createResourceWithLabelAndProperties(String name, String label, Map properties) { + if (name != null && label != null && properties != null) { + LockableResource existent = fromName(name); + if (existent == null) { + LockableResource resource = new LockableResource(name); + resource.setLabels(label); + resource.setProperties( + properties.entrySet().stream().map(e -> { + LockableResourceProperty p = new LockableResourceProperty(); + p.setName(e.getKey()); + p.setValue(e.getValue()); + return p; + }).collect(Collectors.toList())); + getResources().add(resource); + save(); + return true; + } + } + return false; + } + /** * Reserves an available resource for the userName indefinitely (until that person, or some * explicit scripted action, decides to release the resource). @@ -873,13 +896,13 @@ public synchronized void unreserve(List resources) { return; } else { unreserveResources(resources); - List resourceNamesToLock = new ArrayList<>(); + LinkedHashMap> resourcesToLock = new LinkedHashMap<>(); // lock all (old and new resources) for (LockableResource requiredResource : requiredResourceForNextContext) { try { requiredResource.setBuild(nextContext.getContext().get(Run.class)); - resourceNamesToLock.add(requiredResource.getName()); + resourcesToLock.put(requiredResource.getName(), requiredResource.getProperties()); } catch (Exception e) { // skip this context, as the build cannot be retrieved (maybe it was deleted while // running?) @@ -897,7 +920,7 @@ public synchronized void unreserve(List resources) { // continue with next context LockStepExecution.proceed( - resourceNamesToLock, + resourcesToLock, nextContext.getContext(), nextContext.getResourceDescription(), nextContext.getVariableName(), @@ -1153,7 +1176,7 @@ public synchronized List checkResourcesAvailability( } // Find remaining resources - LinkedHashSet allSelected = new LinkedHashSet<>(); + List allSelected = new ArrayList<>(); for (LockableResourcesCandidatesStruct requiredResources : requiredResourcesCandidatesList) { List candidates = requiredResources.candidates; @@ -1202,7 +1225,7 @@ public synchronized List checkResourcesAvailability( allSelected.addAll(selected); } - return new ArrayList<>(allSelected); + return allSelected; } /* diff --git a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java index bf4873c55..ccbeca0e6 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/queue/LockRunListener.java @@ -18,11 +18,13 @@ import hudson.model.TaskListener; import hudson.model.listeners.RunListener; import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Logger; import java.util.stream.Collectors; import org.jenkins.plugins.lockableresources.LockableResource; +import org.jenkins.plugins.lockableresources.LockableResourceProperty; import org.jenkins.plugins.lockableresources.LockableResourcesManager; import org.jenkins.plugins.lockableresources.actions.LockedResourcesBuildAction; import org.jenkins.plugins.lockableresources.actions.ResourceVariableNameAction; @@ -44,52 +46,54 @@ public void onStarted(Run build, TaskListener listener) { if (build instanceof AbstractBuild) { Job proj = Utils.getProject(build); List required = new ArrayList<>(); - LockableResourcesStruct resources = Utils.requiredResources(proj); - - if (resources != null) { - if (resources.requiredNumber != null || !resources.label.isEmpty() || resources.getResourceMatchScript() != null) { - required.addAll(LockableResourcesManager.get(). - getResourcesFromProject(proj.getFullName())); - } else { - required.addAll(resources.required); - } + LockableResourcesStruct resources = Utils.requiredResources(proj); + + if (resources != null) { + if (resources.requiredNumber != null || !resources.label.isEmpty() || resources.getResourceMatchScript() != null) { + required.addAll(LockableResourcesManager.get(). + getResourcesFromProject(proj.getFullName())); + } else { + required.addAll(resources.required); + } - // make sure each entry is unique - required = new ArrayList<>(new LinkedHashSet<>(required)); - - if (LockableResourcesManager.get().lock(required, build, null)) { - build.addAction(LockedResourcesBuildAction - .fromResources(required)); - listener.getLogger().printf("%s acquired lock on %s%n", - LOG_PREFIX, required); - LOGGER.fine(build.getFullDisplayName() - + " acquired lock on " + required); - if (resources.requiredVar != null) { - List envsToSet = new ArrayList<>(); - - // add the comma separated list of names acquired - envsToSet.add(new StringParameterValue( - resources.requiredVar, - required.stream() - .map(LockableResource::getName) - .collect(Collectors.joining(",")))); - - // also add a numbered variable for each acquired lock - int index = 0; - for (LockableResource lr : required) { - envsToSet.add(new StringParameterValue(resources.requiredVar + index, lr.getName())); - ++index; + if (LockableResourcesManager.get().lock(required, build, null)) { + build.addAction(LockedResourcesBuildAction + .fromResources(required)); + listener.getLogger().printf("%s acquired lock on %s%n", + LOG_PREFIX, required); + LOGGER.fine(build.getFullDisplayName() + + " acquired lock on " + required); + if (resources.requiredVar != null) { + List envsToSet = new ArrayList<>(); + + // add the comma separated list of names acquired + envsToSet.add(new StringParameterValue( + resources.requiredVar, + required.stream() + .map(LockableResource::getName) + .collect(Collectors.joining(",")))); + + // also add a numbered variable for each acquired lock along with properties of the lock + int index = 0; + for (LockableResource lr : required) { + String lockEnvName = resources.requiredVar + index; + envsToSet.add(new StringParameterValue(lockEnvName, lr.getName())); + for (LockableResourceProperty lockProperty : lr.getProperties()) { + String propEnvName = lockEnvName + "_" + lockProperty.getName(); + envsToSet.add(new StringParameterValue(propEnvName, lockProperty.getValue())); } - - build.addAction(new ResourceVariableNameAction(envsToSet)); + ++index; } - } else { - listener.getLogger().printf("%s failed to lock %s%n", - LOG_PREFIX, required); - LOGGER.fine(build.getFullDisplayName() + " failed to lock " - + required); + + build.addAction(new ResourceVariableNameAction(envsToSet)); } + } else { + listener.getLogger().printf("%s failed to lock %s%n", + LOG_PREFIX, required); + LOGGER.fine(build.getFullDisplayName() + " failed to lock " + + required); } + } } } diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.jelly index 5006106d7..df4a099a7 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.jelly @@ -23,4 +23,13 @@ + + + +
+ +
+
+
+
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.properties index 7764bb1dd..29239d255 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResource/config.properties @@ -23,4 +23,7 @@ entry.name.title=Name entry.description.title=Description entry.labels.title=Labels -entry.reservedBy.title=Reserved by \ No newline at end of file +entry.reservedBy.title=Reserved by +entry.properties.title=Properties +entry.properties.add=Add Property +entry.properties.delete=Delete Property \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.jelly new file mode 100644 index 000000000..561b3f24d --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.jelly @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.properties b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.properties new file mode 100644 index 000000000..3034bf1f9 --- /dev/null +++ b/src/main/resources/org/jenkins/plugins/lockableresources/LockableResourceProperty/config.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright 2022 Martin Pokorny. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +entry.name.title=Name +entry.value.title=Value \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly index c68d08565..66910bf62 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableResources/table.jelly @@ -29,7 +29,6 @@ THE SOFTWARE. xmlns:i="jelly:fmt" xmlns:st="jelly:stapler" > - @@ -39,7 +38,7 @@ THE SOFTWARE. id="lockable-resources" data-remember-search-text="true" isLoaded="true" - data-columns-definition="[null, null, null, null, null, null]" + data-columns-definition="[null, null, null, null, null, null, null]" data-table-configuration="{}" >
@@ -53,6 +52,8 @@ THE SOFTWARE. + + @@ -62,10 +63,11 @@ THE SOFTWARE. + - + + + - + @@ -58,13 +72,13 @@ THE SOFTWARE. - - - - - - - + + + + + + + @@ -320,4 +334,7 @@ THE SOFTWARE.
${%resources.table.column.status} ${%resources.table.column.timestamp} ${%resources.table.column.labels}${%resources.table.column.properties} ${%resources.table.column.action}
- + ${label} + +
+ + + + + + + + + +
${property.name}${property.value}
+
+
+
${i + 1}${idx.index + 1}
${%resources.table.column.index}${%resources.table.column.resource}${%resources.table.column.status}${%resources.table.column.timestamp}${%resources.table.column.labels}${%resources.table.column.properties}${%resources.table.column.action}${%resources.table.column.index}${%resources.table.column.resource}${%resources.table.column.status}${%resources.table.column.timestamp}${%resources.table.column.labels}${%resources.table.column.properties}${%resources.table.column.action}
-

${%queue.warning.count(queue.size(), h.getTimeSpanString(oldestQueue.getQueuedTimestamp()))}

+ + +

${%queue.warning.count(queue.getAll().size(), h.getTimeSpanString(oldestQueue.getQueuedTimestamp()))}

${%queue.warning.count.detail}
@@ -51,53 +51,124 @@ THE SOFTWARE. id="lockable-resources-queue" isLoaded="true" data-remember-search-text="true" - data-columns-definition="[null, null, null, null, null]" + data-columns-definition="[null, null, null, null, null, null]" data-table-configuration="{}" > - - - - - - - - - - - - + ${%queue.table.column.index} ${%queue.table.column.request.type} ${%queue.table.column.request.info} + ${%queue.table.column.reason} ${%queue.table.column.requested.by} ${%queue.table.column.requested.at} - ${%queue.table.column.reason} - - - - - - - - - - ${build.fullDisplayName} - - - ${%N/A} - - - - - - ${%ago(h.getTimeSpanString(queuedResource.getQueuedTimestamp()))} - - - - - + + + ${idx.index + 1} + + + + ${%type.resources} + + +
+
+
+ ${resource.name} +
+
+ + ${%resources.ephemeral} + +
+
+ +
+
+ ${resource.description} +
+
+
+
+ + + + + ${%resource.status.reservedBy(resource.reservedBy)} + + + ${%resource.status.locked(rootURL + '/' + resource.build.url, resource.build.fullDisplayName)} + + + ${%resource.status.queuedBy(resource.queueItemProject, resource.queueItemId)} + + + + ${%resource.status.free} + + + + ${%ago(h.getTimeSpanString(resource.reservedTimestamp))} + + +
+
+ + + + ${%type.label} + + + ${queuedItem.requiredLabel} + + + + + + + ${%label.requiredNumber(queuedItem.requiredNumber)} + + + ${%label.requiredAll} + + + + + + + + + ${%type.groovy} + ${%groovy.code} + ${%groovy.status} + + + + ${%N/A} + ${%N/A} + ${%N/A} + +
+ + + + + ${build.fullDisplayName} + + + ${%N/A} + + + + + + ${%ago(h.getTimeSpanString(queuedItem.getQueuedTimestamp()))} + + +
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties index 6ceec1861..9d98c3648 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockableResourcesRootAction/tableQueue/table.properties @@ -29,6 +29,7 @@ This can happen when Jenkins crashes and the builds are no longer executable aft Please check the status and manually release the resource if necessary. If you do not have permission to release the resource, contact your administrator. +queue.table.column.index=Index queue.table.column.request.type=Request type queue.table.column.request.info=Request queue.table.column.requested.by=Requested by @@ -43,4 +44,19 @@ resource.status.queuedBy=QUEUED by {0} {1} ago={0} ago label.requiredNumber={0} label(s) are required. label.requiredAll=All possible labels are required. -label.status=Found {1} free resource(s) from {0} possible. \ No newline at end of file +label.status=Found {1} free resource(s) from {0} possible. + + +resource.status.locked=Locked by {1} +resource.status.reservedBy=Reserved by {0} +resource.status.queuedBy=Queued by {0} {1} +resource.status.free=Free +label.requiredNumber=Requested {0} label(s). +label.requiredAll=Requested ALL possible labels. +label.status=
There are {1} resource(s) matched, but only {0} free. +groovy.status=!!!Groovy expression is currently not supported!!! +resources.ephemeral=Ephemeral +groovy.code=!!!Groovy expression is currently not supported!!! +type.resources=Resources +type.label=Label +type.groovy=Groovy expression diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly deleted file mode 100644 index 1bee56b36..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.jelly +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - ${%resource.status.reservedBy(resource.reservedBy)} - - - ${%resource.status.locked(rootURL + '/' + resource.build.url, resource.build.fullDisplayName)} - - - ${%resource.status.queuedBy(resource.queueItemProject, resource.queueItemId)} - - - - ${%resource.status.free} - - - - ${%ago(h.getTimeSpanString(resource.reservedTimestamp))} - - - - - - - - - ${%label.requiredNumber(queuedResource.requiredNumber)} - - - ${%label.requiredAll} - - - ${%label.status(it.getFreeResourceAmount(queuedResource.label), it.getAssignedResourceAmount(queuedResource.label))} - - - - - - ${%groovy.status} - - - - - ${%N/A} - - - - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties deleted file mode 100644 index 75d4211e2..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/reason/cell.properties +++ /dev/null @@ -1,34 +0,0 @@ -# The MIT License -# -# Copyright 2023 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -resource.status.locked=Locked by {1} -resource.status.reservedBy=Reserved by {0} -resource.status.queuedBy=Queued by {0} {1} -resource.status.free=Free - -label.requiredNumber=Requested {0} label(s). -label.requiredAll=Requested ALL possible labels. -label.status=
There are {1} resource(s) matched, but only {0} free. - -groovy.status=!!!Groovy expression is currently not supported!!! - -ago={0} ago \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly deleted file mode 100644 index 17f4b1d93..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.jelly +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - -
-
-
- ${resource.name} -
-
- - ${%resources.ephemeral} - -
-
- -
-
- ${resource.description} -
-
-
-
-
-
- - - - - ${queuedResource.label} - - - - - - - - ${%groovy.code} - - - - - ${%N/A} - - -
-
diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties deleted file mode 100644 index f4de898e7..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request/cell.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2023 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -resources.ephemeral=Ephemeral - -groovy.code=!!!Groovy expression is currently not supported!!! \ No newline at end of file diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly deleted file mode 100644 index 022ae5151..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.jelly +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - ${%type.resources} - - - - ${%type.label} - - - - - ${%type.groovy} - - - - ${%N/A} - - - diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties b/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties deleted file mode 100644 index 79cc4f277..000000000 --- a/src/main/resources/org/jenkins/plugins/lockableresources/queue/LockableResourcesStruct/request_type/cell.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright 2023 Martin Pokorny. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -type.resources=Resources -type.label=Label -type.groovy=Groovy expression \ No newline at end of file From ce79091d7ec6934c303f8773b51a6937a3527501 Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sat, 25 Nov 2023 00:02:42 +0100 Subject: [PATCH 0904/1078] Improve tests (#581) Improve tests --- .../lockableresources/LockableResourcesManager.java | 13 +++++++++++-- .../lockableresources/ConfigurationAsCodeTest.java | 9 +++++++++ .../lockableresources/DeclarativePipelineTest.java | 10 ++++++++++ .../lockableresources/FreeStyleProjectTest.java | 11 +++++++++++ .../lockableresources/InteroperabilityTest.java | 9 +++++++++ .../lockableresources/LockStepHardKillTest.java | 4 +++- .../lockableresources/LockableResourceApiTest.java | 9 +++++++++ .../plugins/lockableresources/NodesMirrorTest.java | 13 ++++++++++++- 8 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index fe6b64e1f..0805bb6d2 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -264,6 +264,15 @@ public synchronized LockableResource fromName(String resourceName) { return null; } + // --------------------------------------------------------------------------- + /** Checks if given resource exist. */ + @NonNull + @Restricted(NoExternalUse.class) + public boolean resourceExist(@CheckForNull String resourceName) { + return this.fromName(resourceName) != null; + } + + // --------------------------------------------------------------------------- public synchronized boolean queue(List resources, long queueItemId, String queueProjectName) { for (LockableResource r : resources) { if (r.isReserved() || r.isQueued(queueItemId) || r.isLocked()) { @@ -1256,11 +1265,11 @@ public static LockableResourcesManager get() { @Override public synchronized void save() { if (enableSave == -1) { - // read system property and chache it. + // read system property and cache it. enableSave = SystemProperties.getBoolean(Constants.SYSTEM_PROPERTY_DISABLE_SAVE) ? 0 : 1; } - if (enableSave == 0) return; // savinig is disabled + if (enableSave == 0) return; // saving is disabled if (BulkChange.contains(this)) return; // no change detected diff --git a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java index 95c46477b..74c5d3dd2 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/ConfigurationAsCodeTest.java @@ -11,11 +11,20 @@ import io.jenkins.plugins.casc.misc.Util; import io.jenkins.plugins.casc.model.CNode; import java.util.List; +import org.jenkins.plugins.lockableresources.util.Constants; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; public class ConfigurationAsCodeTest { + // --------------------------------------------------------------------------- + @Before + public void setUp() { + // to speed up the test + System.setProperty(Constants.SYSTEM_PROPERTY_DISABLE_SAVE, "true"); + } + @ClassRule @ConfiguredWithCode("configuration-as-code.yml") public static JenkinsConfiguredWithCodeRule r = new JenkinsConfiguredWithCodeRule(); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java b/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java index f0dee36d0..9bb2250b5 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/DeclarativePipelineTest.java @@ -4,14 +4,24 @@ import com.google.common.base.Joiner; import hudson.model.Result; +import org.jenkins.plugins.lockableresources.util.Constants; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; public class DeclarativePipelineTest { + + // --------------------------------------------------------------------------- + @Before + public void setUp() { + // to speed up the test + System.setProperty(Constants.SYSTEM_PROPERTY_DISABLE_SAVE, "true"); + } + @Rule public JenkinsRule j = new JenkinsRule(); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java index 216031751..a23e9d62a 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/FreeStyleProjectTest.java @@ -30,9 +30,11 @@ import jenkins.model.Jenkins; import org.jenkins.plugins.lockableresources.actions.LockableResourcesRootAction; import org.jenkins.plugins.lockableresources.queue.LockableResourcesQueueTaskDispatcher; +import org.jenkins.plugins.lockableresources.util.Constants; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -45,6 +47,13 @@ public class FreeStyleProjectTest { @Rule public JenkinsRule j = new JenkinsRule(); + // --------------------------------------------------------------------------- + @Before + public void setUp() { + // to speed up the test + System.setProperty(Constants.SYSTEM_PROPERTY_DISABLE_SAVE, "true"); + } + @Test @Issue("JENKINS-34853") public void security170fix() throws Exception { @@ -209,7 +218,9 @@ public void approvalRequired() throws Exception { @Test public void autoCreateResource() throws IOException, InterruptedException, ExecutionException { FreeStyleProject f = j.createFreeStyleProject("f"); + assertNull(LockableResourcesManager.get().fromName("resource1")); f.addProperty(new RequiredResourcesProperty("resource1", null, null, null, null)); + assertNull(LockableResourcesManager.get().fromName("resource1")); FreeStyleBuild fb1 = f.scheduleBuild2(0).waitForStart(); j.waitForMessage("acquired lock on [resource1]", fb1); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java index c0b51b609..ed2065f5d 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/InteroperabilityTest.java @@ -6,9 +6,11 @@ import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import java.util.concurrent.Semaphore; +import org.jenkins.plugins.lockableresources.util.Constants; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -16,6 +18,13 @@ public class InteroperabilityTest extends LockStepTestBase { + // --------------------------------------------------------------------------- + @Before + public void setUp() { + // to speed up the test + System.setProperty(Constants.SYSTEM_PROPERTY_DISABLE_SAVE, "true"); + } + @Rule public JenkinsRule j = new JenkinsRule(); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java index 1e25bbf15..6d08a1e72 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockStepHardKillTest.java @@ -21,7 +21,7 @@ public class LockStepHardKillTest extends LockStepTestBase { @Issue("JENKINS-36479") @Test public void hardKillNewBuildClearsLock() throws Exception { - LockableResourcesManager.get().createResource("resource1"); + LockableResourcesManager.get().createResourceWithLabel("resource1", "label"); WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "p1"); p1.setDefinition(new CpsFlowDefinition( @@ -105,6 +105,7 @@ public void hardKillWithWaitingRuns() throws Exception { LockableResourcesManager.get().createResource("resource1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( + /// FIXME why we need retry here, when you know it, write the comment here or remove it "retry(99) {\n" + " lock('resource1') {\n" + " semaphore('wait-inside')\n" + " }\n" + "}", true)); @@ -134,6 +135,7 @@ public void hardKillWithWaitingRunsOnLabel() throws Exception { LockableResourcesManager.get().createResourceWithLabel("resource2", "label1"); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( + /// FIXME why we need retry here, when you know it, write the comment here or remove it "retry(99) {\n" + " lock(label: 'label1', quantity: 1) {\n" + " semaphore('wait-inside')\n" diff --git a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceApiTest.java b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceApiTest.java index d52affd23..3a7a12666 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceApiTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/LockableResourceApiTest.java @@ -9,6 +9,8 @@ import hudson.security.FullControlOnceLoggedInAuthorizationStrategy; import org.htmlunit.FailingHttpStatusCodeException; +import org.jenkins.plugins.lockableresources.util.Constants; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -16,6 +18,13 @@ public class LockableResourceApiTest { + // --------------------------------------------------------------------------- + @Before + public void setUp() { + // to speed up the test + System.setProperty(Constants.SYSTEM_PROPERTY_DISABLE_SAVE, "true"); + } + @Rule public JenkinsRule j = new JenkinsRule(); diff --git a/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java b/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java index 2f7371de8..3a70d4eb3 100644 --- a/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java +++ b/src/test/java/org/jenkins/plugins/lockableresources/NodesMirrorTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import java.util.logging.Logger; import org.jenkins.plugins.lockableresources.util.Constants; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; @@ -15,6 +16,8 @@ public class NodesMirrorTest { + private static final Logger LOGGER = Logger.getLogger(NodesMirror.class.getName()); + @Rule public final JenkinsRule j = new JenkinsRule(); @@ -22,14 +25,22 @@ public class NodesMirrorTest { public void mirror_few_nodes() throws Exception { System.setProperty(Constants.SYSTEM_PROPERTY_ENABLE_NODE_MIRROR, "true"); + LOGGER.info("add agent: FirstAgent"); j.createSlave("FirstAgent", "label label2", null); + LOGGER.info("add agent: SecondAgent"); j.createSlave("SecondAgent", null, null); // this is asynchronous operation, so wait until resources are created. - for (int i = 1; LockableResourcesManager.get().fromName("SecondAgent") != null && i <= 10; i++) { + LOGGER.info("wait for resources"); + for (int i = 1; + !LockableResourcesManager.get().resourceExist("FirstAgent") + && !LockableResourcesManager.get().resourceExist("SecondAgent") + && i <= 10; + i++) { Thread.sleep(100); } + LOGGER.info("check agent: FirstAgent"); LockableResource firstAgent = LockableResourcesManager.get().fromName("FirstAgent"); assertEquals("FirstAgent", firstAgent.getName()); From 1ad65ecea11522c880b4012733b6538177c3c94d Mon Sep 17 00:00:00 2001 From: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com> Date: Sat, 25 Nov 2023 00:05:00 +0100 Subject: [PATCH 0905/1078] Show used resources in build page (#583) --- .../lockableresources/LockStepExecution.java | 9 +- .../actions/LockedResourcesBuildAction.java | 86 ++++++++++++++++- .../lockableresources/Messages.properties | 1 + .../LockedResourcesBuildAction/index.jelly | 95 ++++++++++++++----- .../index.properties | 11 ++- 5 files changed, 170 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java index e34acfb09..ca45db46a 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockStepExecution.java @@ -16,6 +16,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import org.jenkins.plugins.lockableresources.actions.LockedResourcesBuildAction; import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; @@ -110,10 +111,10 @@ public static void proceed( String resourceDescription, final String variable, boolean inversePrecedence) { - Run r; + Run build; FlowNode node; try { - r = context.get(Run.class); + build = context.get(Run.class); node = context.get(FlowNode.class); context.get(TaskListener.class).getLogger().println("Lock acquired on [" + resourceDescription + "]"); } catch (Exception e) { @@ -121,8 +122,10 @@ public static void proceed( return; } - LOGGER.finest("Lock acquired on [" + resourceDescription + "] by " + r.getExternalizableId()); + LOGGER.finest("Lock acquired on [" + resourceDescription + "] by " + build.getExternalizableId()); try { + + LockedResourcesBuildAction.updateAction(build, new ArrayList<>(lockedResources.keySet())); PauseAction.endCurrentPause(node); BodyInvoker bodyInvoker = context.newBodyInvoker() .withCallback(new Callback( diff --git a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java index 47581c371..477b7e8cc 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction.java @@ -9,65 +9,145 @@ package org.jenkins.plugins.lockableresources.actions; import hudson.model.Action; +import hudson.model.Run; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.jenkins.plugins.lockableresources.LockableResource; +import org.jenkins.plugins.lockableresources.LockableResourcesManager; +import org.jenkins.plugins.lockableresources.Messages; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +// ----------------------------------------------------------------------------- +/** BuildAction for lockable resources. + * Shows usage of resources in the build page. + * url: jobUrl/buildNr/locked-resources/ + */ +@Restricted(NoExternalUse.class) public class LockedResourcesBuildAction implements Action { + // ------------------------------------------------------------------------- private final List lockedResources; + // ------------------------------------------------------------------------- public LockedResourcesBuildAction(List lockedResources) { this.lockedResources = lockedResources; } + // ------------------------------------------------------------------------- public List getLockedResources() { return lockedResources; } + // ------------------------------------------------------------------------- @Override public String getIconFileName() { return LockableResourcesRootAction.ICON; } + // ------------------------------------------------------------------------- @Override public String getDisplayName() { - return "Locked Resources"; + return Messages.LockedResourcesBuildAction_displayName(); } + // ------------------------------------------------------------------------- @Override public String getUrlName() { return "locked-resources"; } + // ------------------------------------------------------------------------- + /** Adds *resourceNames* to *build*. + * When the action does not exists, will be created as well. + * When the resource has been used by this build just now, the counter will + * increased to eliminate multiple entries. + * Used in pipelines - lock() step + */ + @Restricted(NoExternalUse.class) + public static void updateAction(Run build, List resourceNames) { + LockedResourcesBuildAction action = build.getAction(LockedResourcesBuildAction.class); + + if (action == null) { + List resPojos = new ArrayList<>(); + action = new LockedResourcesBuildAction(resPojos); + build.addAction(action); + } + + for (String name : resourceNames) { + LockableResource r = LockableResourcesManager.get().fromName(name); + action.add(new ResourcePOJO(r)); + } + } + + // ------------------------------------------------------------------------- + /** Add the resource to build action.*/ + @Restricted(NoExternalUse.class) + private void add(ResourcePOJO r) { + for (ResourcePOJO pojo : this.lockedResources) { + if (pojo.getName().equals(r.getName())) { + pojo.inc(); + return; + } + } + this.lockedResources.add(r); + } + + // ------------------------------------------------------------------------- + /** Create action from resources. + * Used in free-style projects. + */ + @Restricted(NoExternalUse.class) public static LockedResourcesBuildAction fromResources(Collection resources) { List resPojos = new ArrayList<>(); for (LockableResource r : resources) resPojos.add(new ResourcePOJO(r)); return new LockedResourcesBuildAction(resPojos); } + // ------------------------------------------------------------------------- public static class ResourcePOJO { + // --------------------------------------------------------------------- private String name; private String description; + private int count = 1; + // --------------------------------------------------------------------- public ResourcePOJO(String name, String description) { this.name = name; this.description = description; } + // --------------------------------------------------------------------- public ResourcePOJO(LockableResource r) { this.name = r.getName(); this.description = r.getDescription(); } + // --------------------------------------------------------------------- public String getName() { - return name; + return this.name; } + // --------------------------------------------------------------------- public String getDescription() { - return description; + return this.description; + } + + // --------------------------------------------------------------------- + /** Return the counter, how many was / is the resource used in the build. + * Example: you can use the lock() function in parallel stages for the + * same resource. + */ + public int getCounter() { + return this.count; + } + + // --------------------------------------------------------------------- + /** Increment counter */ + public void inc() { + this.count++; } } } diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties index f53e5256f..7c85b5e1a 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties +++ b/src/main/resources/org/jenkins/plugins/lockableresources/Messages.properties @@ -20,6 +20,7 @@ LockableResourcesRootAction.StealPermission.Description=This permission grants t LockableResourcesRootAction.ViewPermission=View LockableResourcesRootAction.ViewPermission.Description=This permission grants the ability to view \ lockable resources. +LockedResourcesBuildAction.displayName=Used lockable resources # Java errors error.labelDoesNotExist=The resource label does not exist: {0}. error.resourceDoesNotExist=The resource does not exist: {0}. diff --git a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index.jelly b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index.jelly index 13e80efde..0cace6df6 100644 --- a/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index.jelly +++ b/src/main/resources/org/jenkins/plugins/lockableresources/actions/LockedResourcesBuildAction/index.jelly @@ -1,34 +1,83 @@ - + + - - + + + + + - + + -

${%header.resources}

-

${%header.resources.list}

-
    - -
  • - ${resource.name} - ${resource.description} -
  • -
    -
+ + + + ${%app.bar.resources} + + + + + + + +
+ + + + + + + + + + + + + + + + + +
${%table.column.index}${%table.column.name}${%table.column.description}${%table.column.counter}
${idx.index + 1}${resource.name}${resource.description}${resource.counter}
+
+ +
@@ -94,8 +98,8 @@ THE SOFTWARE.