2 | Acciones a realizar cuando transcurra el tiempo máximo de ejecución (timeout).
3 | Si no se especifica nada se utilizará "Abortar la ejecución".
4 |
2 | Continue subsequent timeout actions even when the build step failed.
3 | If unchecked, subsequent timeout actions is not executed, and the build will be marked as failure.
4 |
2 | List "Perform BuildStep" in timeout actions.
3 | This feature is provided as-is and not supported even it does not work correctly with some build steps.
4 |
2 | Seconds to detect timeout since the last log output.
3 | This is useful to terminate a build if there has not been any activity for a long time.
4 | Be careful with log output delay for buffering.
5 |
2 | Realizar un paso de ejecución o acción post-ejecución como una acción de tiempo máximo.
3 | Esto en ningún caso garantiza que todos los pasos y acciones post-ejecución funcionen de forma correcta.
4 |
2 | If a build takes longer than this percentage of the n most recent non-failing builds,
3 | the build will be terminated. If there are no such builds, the "Timeout minutes" field
4 | will be used instead.
5 |
2 | Continuar con las acciones posteriores una vez transcurrido el tiempo máximo incluso si el paso de ejecución falló.
3 | Si no se marca, dichas acciones posteriores no se ejecutarán y la ejecución se marcará como fallida.
4 |
2 | Listar "Realizar paso de ejecución" en acciones de tiempo máximo (timeout).
3 | Esta funcionalidad se proporciona como está y puede no estar soportada dependiendo de los tipos de pasos de ejecución.
4 |
2 | Si la ejecución no se completa en el tiempo indicado (en minutos, 3 como mínimo), se terminará
3 | automáticamente marcándola como abortada. Esto es útil por ejemplo si ha experimentado bucles
4 | infinitos en sus tests.
5 |
2 | If configured, and if a build does not complete by the specified amount of time (in minutes;
3 | at least 3), then the build will be terminated automatically. This is
4 | useful if you have experienced infinite loops in your test, for example.
5 |
2 | Segundos para detectar el tiempo máximo desde la última traza generada.
3 | Esto es útil para abortar una ejecución si ésta no tiene actividad durante mucho tiempo.
4 | Tenga cuidado con el retraso introducido por el buffering en la generación de trazas.
5 |
2 | If configured, and if a build does not complete by next deadline time (specified in 24-hour format as HH:MM:SS or HH:MM),
3 | then the build will be terminated automatically.
4 |
5 | Variable references are allowed to define deadline time.
6 |
2 | Si una ejecución no se completa antes de la siguiente fecha tope (especificada como la hora del día en formato 24 horas: HH:MM:SS o HH:MM),
3 | se terminará automáticamente.
4 |
5 | Se permite la utilización de variables para definir la hora de la fecha tope.
6 |
2 | Si la ejecución dura más que este porcentaje de las tres últimas más recientes sin fallos,
3 | se terminará como abortada. Si no hubiera ejecuciones correctas anteriores, entonces se utilizaría
4 | el tiempo indicado en "Tiempo máximo a utilizar si no hay ejecuciones anteriores correctas o fallidas"
5 | en su lugar.
6 |
2 | Period in minutes after the deadline time when a build should be immediately terminated. E.g. if deadline is defined as "13:50",
3 | tolerance as "5" minutes and build is scheduled to run at "13:52" it will be immediately terminated. However if it is scheduled at "13:56",
4 | build's deadline will be set at "13:50" of next day.
5 |
2 | Build steps like "Execute shell", "Execute Windows batch command" and so on, requires Launcher object to execute an external program.
3 | Build Timeout does not provide Launcher for build steps by default and those build steps fail.
4 | Checking here provides the build step a new created Launcher.
5 | You should not check here as long as the build step can run without this (that is, it does not require an external program).
6 |
2 | Periodo de margen tras el instante de la fecha tope para abortar inmediatamente la ejecución de un proyecto. P.e. si se define una fecha tope para un proyecto a las "13:50",
3 | una tolerancia de "5" minutos y se planifica una ejecución a las "13:52", ésta no llegará a producirse porque se aboratará inmediatamente. Por el contrario si se planifica
4 | para las "13:56", se establecerá como fecha tope de la ejecución las "13:50" del día siguiente.
5 |
2 | Los pasos de ejecución como "Ejecutar línea de comandos (shell)" o "Ejecutar línea de comandos de Windows" requieren de un objeto lanzador para ejecutar un programa externo.
3 | El tiempo máximo de ejecución no proporciona lanzador para los pasos por defecto y esos pasos fallarán.
4 | Habilitar esta opción proporciona al paso de ejecución un nuevo lanzador.
5 | No debería habilitarse si el paso de ejecución puede realizarse sin un lanzador adicional (no hay programa externo que ejecutar).
6 |
7 |
--------------------------------------------------------------------------------
/.github/workflows/jenkins-security-scan.yml:
--------------------------------------------------------------------------------
1 | name: Jenkins Security Scan
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | types: [ opened, synchronize, reopened ]
9 | workflow_dispatch:
10 |
11 | permissions:
12 | security-events: write
13 | contents: read
14 | actions: read
15 |
16 | jobs:
17 | security-scan:
18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
19 | with:
20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
22 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/BuildStepWithTimeout/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/Lifecycle.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import hudson.Extension;
4 | import hudson.init.Terminator;
5 |
6 | import jakarta.inject.Inject;
7 | import java.util.List;
8 | import java.util.concurrent.ScheduledExecutorService;
9 | import java.util.logging.Logger;
10 |
11 | @Extension
12 | @SuppressWarnings("unused")
13 | public class Lifecycle {
14 | private static final Logger log = Logger.getLogger(Lifecycle.class.getName());
15 | private final ScheduledExecutorService scheduler;
16 |
17 | /**
18 | * Unused - required by sezpoz
19 | */
20 | public Lifecycle() {
21 | this(null);
22 | }
23 |
24 | @Inject
25 | public Lifecycle(@TimeOut ScheduledExecutorService scheduler) {
26 | this.scheduler = scheduler;
27 | }
28 |
29 | @Terminator
30 | public void shutdown() {
31 | log.fine(() -> "Shutting down Global TimeOut ScheduledExecutorService...");
32 | List timeOuts = scheduler.shutdownNow();
33 | log.info(() -> String.format("Shutdown complete - Global TimeOut ScheduledExecutorService had %d tasks pending", timeOuts.size()));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/global/GlobalTimeOutConfiguration/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_13/jobs/NoActivityTimeOutStrategy/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 |
7 |
8 | true
9 | false
10 | false
11 | false
12 |
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 5000
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/FakeBuildStep.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout;
2 |
3 | import hudson.Extension;
4 | import hudson.Launcher;
5 | import hudson.model.AbstractBuild;
6 | import hudson.model.AbstractProject;
7 | import hudson.model.BuildListener;
8 | import hudson.tasks.BuildStep;
9 | import hudson.tasks.BuildStepDescriptor;
10 | import hudson.tasks.Builder;
11 |
12 | public class FakeBuildStep extends Builder implements BuildStep {
13 | static final String FAKE_BUILD_STEP_OUTPUT = "fake-build-step-output";
14 | private long delay = 0;
15 |
16 | FakeBuildStep(long delay) {
17 | this.delay = delay;
18 | }
19 |
20 | @Override
21 | public boolean perform(AbstractBuild, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException {
22 | Thread.sleep(delay);
23 |
24 | listener.getLogger().print(FAKE_BUILD_STEP_OUTPUT);
25 |
26 | return true;
27 | }
28 |
29 | @Extension
30 | public static class DescriptorImpl extends BuildStepDescriptor {
31 |
32 | public boolean isApplicable(Class extends AbstractProject> jobType) {
33 | return false;
34 | }
35 |
36 | public String getDisplayName() {
37 | return null;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2012, Sun Microsystems, Inc., Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Description=\u8aac\u660e
24 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Timeout\ seconds=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u9593 (\u79d2)
24 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2012, Sun Microsystems, Inc., Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Timeout\ minutes=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8(\u5206)
24 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/AbortAndRestartOperation/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2016, Sun Microsystems, Inc., Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Maximum\ restarts=\u6700\u5927\u518d\u8d77\u52d5\u56de\u6570
24 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/GlobalTimeOutModule.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
4 | import com.google.inject.AbstractModule;
5 | import com.google.inject.Provides;
6 | import hudson.Extension;
7 |
8 | import jakarta.inject.Singleton;
9 | import java.util.HashMap;
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.ScheduledExecutorService;
12 | import java.util.concurrent.ScheduledThreadPoolExecutor;
13 |
14 | @Extension
15 | @SuppressWarnings("unused")
16 | public class GlobalTimeOutModule extends AbstractModule {
17 | @Override
18 | protected void configure() {
19 | bind(TimeOutProvider.class).to(GlobalTimeOutConfiguration.class);
20 | }
21 |
22 | @TimeOut
23 | @Provides
24 | @Singleton
25 | ScheduledExecutorService providesScheduler() {
26 | ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder()
27 | .setNameFormat("timeout-%d")
28 | .build());
29 | executor.setRemoveOnCancelPolicy(true);
30 | return Executors.unconfigurableScheduledExecutorService(executor);
31 | }
32 |
33 | @Provides
34 | @Singleton
35 | TimeOutStore providesTimeOutStore() {
36 | return new InMemoryTimeOutStore(new HashMap<>());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_12_2/jobs/AbortWithDescription/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 |
7 |
8 | true
9 | false
10 | false
11 | false
12 |
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | false
27 | true
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_12_2/jobs/FailWithDescription/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 |
7 |
8 | true
9 | false
10 | false
11 | false
12 |
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | true
27 | true
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_12_2/jobs/FailWithoutDescription/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 |
7 |
8 | true
9 | false
10 | false
11 | false
12 |
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | true
27 | false
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_12_2/jobs/AbortWithoutDescription/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 |
7 |
8 | true
9 | false
10 | false
11 | false
12 |
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | false
27 | false
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/global_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Build-timeout\ Plugin\ >\ BuildStep\ Action=Build-timeout Plugin > \u30d3\u30eb\u30c9\u624b\u9806\u306e\u5b9f\u884c
24 | Enable\ BuildStep\ Action=\u300c\u30d3\u30eb\u30c9\u624b\u9806\u306e\u5b9f\u884c\u300d\u3092\u4f7f\u7528\u3059\u308b
25 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2015 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Deadline\ time=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3\u3068\u3059\u308b\u6642\u523b
24 | Deadline\ tolerance\ in\ minutes=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3\u76f4\u5f8c\u306e\u5373\u6642\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u9593 \uff08\u5206\uff09
25 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/QuickBuildTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout;
2 |
3 | import hudson.init.InitMilestone;
4 | import hudson.init.Initializer;
5 | import hudson.model.Items;
6 | import hudson.model.Descriptor;
7 | import hudson.model.Run;
8 |
9 | /**
10 | * Timeout strategy for testing purpose.
11 | */
12 | public class QuickBuildTimeOutStrategy extends BuildTimeOutStrategy {
13 | private final long timeout;
14 |
15 | public QuickBuildTimeOutStrategy() {
16 | this(5000);
17 | }
18 |
19 | public QuickBuildTimeOutStrategy(long milliseconds) {
20 | this.timeout = milliseconds;
21 | }
22 |
23 | @Initializer(after=InitMilestone.PLUGINS_STARTED)
24 | public static void registerAlias() {
25 | // This is extracted from inner of BuildTimeoutWrapperIntegrationTest
26 | Items.XSTREAM2.addCompatibilityAlias(
27 | "hudson.plugins.build_timeout.BuildTimeoutWrapperIntegrationTest$QuickBuildTimeOutStrategy",
28 | QuickBuildTimeOutStrategy.class
29 | );
30 | }
31 |
32 | public Object readResolve()
33 | {
34 | if (timeout == 0) {
35 | return new QuickBuildTimeOutStrategy(5000);
36 | }
37 | return this;
38 | }
39 |
40 | @Override public long getTimeOut(Run run) {
41 | return timeout;
42 | }
43 | @Override public Descriptor getDescriptor() {
44 | throw new UnsupportedOperationException();
45 | }
46 | }
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/BuildStepWithTimeout/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2016-, Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Build\ Step=\u30d3\u30eb\u30c9\u624b\u9806
24 | Time-out\ strategy=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u306e\u5224\u5b9a\u65b9\u6cd5
25 | Time-out\ actions=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u306e\u30a2\u30af\u30b7\u30e7\u30f3
26 | Add\ action=\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u8ffd\u52a0
27 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Build\ Step=\u30d3\u30eb\u30c9\u624b\u9806
24 | Ignore\ failure\ of\ the\ build\ step=\u30d3\u30eb\u30c9\u624b\u9806\u306e\u5931\u6557\u3092\u7121\u8996\u3059\u308b
25 | Create\ a\ launcher\ for\ this\ build\ step=Launcher \u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u4f5c\u6210\u3059\u308b
26 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/build_timeout/operations/BuildStepOperationTest/NoDataBoundConstructorBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/AbortAndRestartOperation/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/InMemoryTimeOutStore.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import java.util.Map;
4 | import java.util.concurrent.ScheduledFuture;
5 | import java.util.logging.Logger;
6 |
7 | public class InMemoryTimeOutStore implements TimeOutStore {
8 | private static final Logger log = Logger.getLogger(InMemoryTimeOutStore.class.getName());
9 | private final Map> map;
10 |
11 | public InMemoryTimeOutStore(Map> map) {
12 | this.map = map;
13 | }
14 |
15 | @Override
16 | public void scheduled(String key, ScheduledFuture> timeOut) {
17 | ScheduledFuture> previous = map.putIfAbsent(key, timeOut);
18 | boolean added = previous == null;
19 | if (added) {
20 | log.fine(() -> String.format("%s time out stored", key));
21 | } else {
22 | log.fine(() -> String.format("%s time out already present - skipping", key));
23 | }
24 | }
25 |
26 | @Override
27 | public void cancel(String key) {
28 | ScheduledFuture> future = map.remove(key);
29 | if (future == null) {
30 | log.fine(() -> String.format("%s time out not found - skipping", key));
31 | return;
32 | }
33 | boolean cancelled = future.cancel(false);
34 | if (cancelled) {
35 | log.fine(() -> String.format("%s time out cancellation succeeded", key));
36 | }
37 | log.fine(() -> String.format("tracking %d global time out(s)", map.size()));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/global.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/Messages_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2010, Sun Microsystems, Inc.
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Descriptor.DisplayName=\u6ede\u7559\u3057\u305f\u5834\u5408\u306b\u30d3\u30eb\u30c9\u3092\u4e2d\u6b62\u3059\u308b
24 | Timeout.Message=\u30d3\u30eb\u30c9\u304c\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u3057\u307e\u3057\u305f({0}\u5206)\u3002\u30d3\u30eb\u30c9\u3092"{1}"\u306b\u5909\u66f4\u3057\u307e\u3059\u3002
25 | Timeout.Aborted=\u4e2d\u6b62
26 | Timeout.Failed=\u5931\u6557
27 | BuildStepWithTimeout.DisplayName=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u4ed8\u304d\u306e\u5b9f\u884c
28 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/Messages.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | AbortOperation.DisplayName=Abort the build
24 | FailOperation.DisplayName=Fail the build
25 | WriteDescriptionOperation.DisplayName=Writing the build description
26 | BuildStepOperation.DisplayName=Perform BuildStep
27 | AbortAndRestartOperation.DisplayName=Abort and restart the build
28 | AbortAndRestartOperation.ScheduledRestart=Scheduled restart of the build (up to {0} times).
29 | AbortAndRestartOperation.InstallNaginator=You need to install naginator-plugin >= 1.16 to restart a build.
30 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2012, Sun Microsystems, Inc., Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Time-out\ actions=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u306e\u30a2\u30af\u30b7\u30e7\u30f3
24 | Add\ action=\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u8ffd\u52a0
25 | Time-out\ strategy=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u306e\u5224\u5b9a\u65b9\u6cd5
26 | Time-out\ variable=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u9593\u306e\u4fdd\u5b58\u5148
27 | Set\ a\ build\ timeout\ environment\ variable=\u4f7f\u7528\u3055\u308c\u305f\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u9593 (\u30df\u30ea\u79d2) \u3092\u4fdd\u5b58\u3059\u308b\u5909\u6570\u540d
28 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/Messages.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | AbsoluteTimeOutStrategy.DisplayName=Absolute
24 | ElasticTimeOutStrategy.DisplayName=Elastic
25 | LikelyStuckTimeOutStrategy.DisplayName=Likely stuck
26 | NoActivityTimeOutStrategy.DisplayName=No Activity
27 |
28 | DeadlineTimeOutStrategy.DisplayName=Deadline
29 | DeadlineTimeOutStrategy.ImmediatelyTerminate=Build timestamp inside deadline tolerance period ({0} + {1} min). Terminating immediately.
30 | DeadlineTimeOutStrategy.NextDeadline=Build allowed to run until deadline: {0}
31 | DeadlineTimeOutStrategy.InvalidDeadlineFormat=Specified deadline time ''{0}'' does not match 24-hour time format (HH:MM or HH:MM:SS)
32 | DeadlineTimeOutStrategy.DeadlineFormatWithMacros=Deadline specified as a variable reference. When evaluated it must match a 24-hour time format (HH:MM or HH:MM:SS)
33 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/operations/Messages_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | AbortOperation.DisplayName=\u30d3\u30eb\u30c9\u3092\u4e2d\u6b62\u3059\u308b
24 | FailOperation.DisplayName=\u30d3\u30eb\u30c9\u3092\u5931\u6557\u6271\u3044\u306b\u3059\u308b
25 | WriteDescriptionOperation.DisplayName=\u30d3\u30eb\u30c9\u306e\u8aac\u660e\u306b\u8ffd\u8a18\u3059\u308b
26 | BuildStepOperation.DisplayName=\u30d3\u30eb\u30c9\u624b\u9806\u306e\u5b9f\u884c
27 | AbortAndRestartOperation.DisplayName=\u30d3\u30eb\u30c9\u306e\u4e2d\u6b62\u3068\u518d\u5b9f\u884c
28 | AbortAndRestartOperation.ScheduledRestart=\u30d3\u30eb\u30c9\u306e\u518d\u5b9f\u884c\u3092\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3057\u307e\u3057\u305f ({0} \u56de\u307e\u3067).
29 | AbortAndRestartOperation.InstallNaginator=\u30d3\u30eb\u30c9\u3092\u518d\u5b9f\u884c\u3059\u308b\u306b\u306f naginator-plugin >= 1.16 \u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u304f\u3060\u3055\u3044\u3002
30 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/config_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2004-2012, Sun Microsystems, Inc., Seiji Sogabe
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | Timeout\ minutes=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8(\u5206)
24 | Timeout\ as\ a\ percentage\ of\ recent\ non-failing\ builds=\
25 | \u5931\u6557\u3057\u3066\u3044\u306a\u3044\u30d3\u30eb\u30c9\u306e\u5e73\u5747\u6240\u8981\u6642\u9593\u304b\u3089\u7b97\u51fa
26 | Timeout\ to\ use\ if\ there\ are\ no\ previous\ successful\ or\ unstable\ builds=\
27 | \u6210\u529f\u3082\u3057\u304f\u306f\u4e0d\u5b89\u5b9a\u30d3\u30eb\u30c9\u304c\u306a\u3044\u5834\u5408\u306e\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8
28 | Number\ of\ Builds=\u30d3\u30eb\u30c9\u306e\u6570
29 | Number\ of\ builds\ to\ consider\ computing\ average\ duration=\u5e73\u5747\u6240\u8981\u6642\u9593\u306e\u7b97\u51fa\u306b\u4f7f\u7528\u3059\u308b\u30d3\u30eb\u30c9\u306e\u6570
30 | Timeout\ minutes\ as\ the\ shortest\ timeout=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u306e\u6700\u5c0f\u5024
31 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/GlobalTimeOutRunListener.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import hudson.Extension;
4 | import hudson.Launcher;
5 | import hudson.model.*;
6 | import hudson.model.listeners.RunListener;
7 |
8 | import edu.umd.cs.findbugs.annotations.NonNull;
9 | import jakarta.inject.Inject;
10 | import jakarta.inject.Singleton;
11 | import java.io.IOException;
12 | import java.time.Duration;
13 | import java.util.Map;
14 | import java.util.concurrent.ScheduledExecutorService;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | @Extension
18 | @Singleton
19 | @SuppressWarnings("unused")
20 | public class GlobalTimeOutRunListener extends RunListener> {
21 | private final ScheduledExecutorService scheduler;
22 | private final TimeOutProvider timeOutProvider;
23 | private final TimeOutStore store;
24 |
25 | /**
26 | * Unused - required by sezpoz
27 | */
28 | public GlobalTimeOutRunListener() {
29 | this(null, null, null);
30 | }
31 |
32 | @Inject
33 | public GlobalTimeOutRunListener(@TimeOut ScheduledExecutorService scheduler, TimeOutProvider timeOutProvider, TimeOutStore store) {
34 | this.scheduler = scheduler;
35 | this.timeOutProvider = timeOutProvider;
36 | this.store = store;
37 | }
38 |
39 | @Override
40 | public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException {
41 | timeOutProvider.timeOutFor(build, listener)
42 | .map(duration -> scheduler.schedule(TimeOutTask.create(timeOutProvider, build, listener, duration),
43 | duration.toMillis(),
44 | TimeUnit.MILLISECONDS))
45 | .ifPresent(future -> store.scheduled(build.getExternalizableId(), future));
46 | return super.setUpEnvironment(build, launcher, listener);
47 | }
48 |
49 | @Override
50 | public void onCompleted(Run, ?> run, @NonNull TaskListener listener) {
51 | store.cancel(run.getExternalizableId());
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/global/InMemoryTimeOutStoreTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.concurrent.ScheduledFuture;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 | import static org.junit.jupiter.api.Assertions.assertTrue;
11 | import static org.mockito.Mockito.mock;
12 | import static org.mockito.Mockito.verify;
13 | import static org.mockito.Mockito.verifyNoInteractions;
14 |
15 | class InMemoryTimeOutStoreTest {
16 | private final Map> map = new HashMap<>();
17 | private final TimeOutStore store = new InMemoryTimeOutStore(map);
18 |
19 | @Test
20 | void shouldKeep() {
21 | store.scheduled("a", mock(ScheduledFuture.class));
22 |
23 | assertEquals(1, map.size());
24 | assertTrue(map.containsKey("a"));
25 | }
26 |
27 | @Test
28 | void shouldNoOpIfKeyAlreadyExists() {
29 | store.scheduled("a", mock(ScheduledFuture.class));
30 | assertEquals(1, map.size());
31 |
32 | store.scheduled("a", mock(ScheduledFuture.class));
33 |
34 | assertEquals(1, map.size());
35 | }
36 |
37 | @Test
38 | void shouldRemoveKeyFromMap() {
39 | store.scheduled("a", mock(ScheduledFuture.class));
40 | store.scheduled("b", mock(ScheduledFuture.class));
41 |
42 | store.cancel("b");
43 |
44 | assertEquals(1, map.size());
45 | assertTrue(map.containsKey("a"));
46 | }
47 |
48 | @Test
49 | void shouldCancel() {
50 | ScheduledFuture> a = mock(ScheduledFuture.class);
51 | ScheduledFuture> b = mock(ScheduledFuture.class);
52 | store.scheduled("a", a);
53 | store.scheduled("b", b);
54 |
55 | store.cancel("b");
56 |
57 | verifyNoInteractions(a);
58 | verify(b).cancel(false);
59 | }
60 |
61 | @Test
62 | void shouldNoOpIfAbsent() {
63 | store.scheduled("a", mock(ScheduledFuture.class));
64 | assertEquals(1, map.size());
65 |
66 | store.cancel("c");
67 |
68 | assertEquals(1, map.size());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/global/GlobalTimeOutRunListenerTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import hudson.Launcher;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.BuildListener;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 | import org.junit.jupiter.api.extension.ExtendWith;
9 |
10 | import org.mockito.Mock;
11 | import org.mockito.junit.jupiter.MockitoExtension;
12 |
13 | import java.io.IOException;
14 | import java.time.Duration;
15 | import java.util.Optional;
16 | import java.util.concurrent.Executors;
17 |
18 | import static org.mockito.ArgumentMatchers.any;
19 | import static org.mockito.ArgumentMatchers.eq;
20 | import static org.mockito.BDDMockito.given;
21 | import static org.mockito.Mockito.verify;
22 | import static org.mockito.Mockito.verifyNoInteractions;
23 |
24 | @ExtendWith(MockitoExtension.class)
25 | class GlobalTimeOutRunListenerTest {
26 | @Mock
27 | private TimeOutProvider timeOutProvider;
28 | @Mock
29 | private TimeOutStore timeOutStore;
30 | private GlobalTimeOutRunListener listener;
31 |
32 | @Mock
33 | private AbstractBuild, ?> build;
34 | @Mock
35 | private Launcher launcher;
36 | @Mock
37 | private BuildListener buildListener;
38 |
39 | @BeforeEach
40 | void setup() {
41 | listener = new GlobalTimeOutRunListener(
42 | Executors.newSingleThreadScheduledExecutor(),
43 | timeOutProvider,
44 | timeOutStore
45 | );
46 | }
47 |
48 | @Test
49 | void shouldStoreIfPresent() throws IOException, InterruptedException {
50 | given(timeOutProvider.timeOutFor(build, buildListener)).willReturn(Optional.of(Duration.ofMillis(1)));
51 | given(build.getExternalizableId()).willReturn("a#1");
52 |
53 | listener.setUpEnvironment(build, launcher, buildListener);
54 |
55 | verify(timeOutStore).scheduled(eq("a#1"), any());
56 | }
57 |
58 | @Test
59 | void shouldNotStoreIfAbsent() throws IOException, InterruptedException {
60 | given(timeOutProvider.timeOutFor(build, buildListener)).willReturn(Optional.empty());
61 |
62 | listener.setUpEnvironment(build, launcher, buildListener);
63 |
64 | verifyNoInteractions(timeOutStore);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/nestedHelp.js:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | Behaviour.register({".build-timeout-nested-help": function(e) {
25 | // ensure Behavior is applied only once.
26 | e.classList.remove("build-timeout-nested-help");
27 | fetch(e.getAttribute("helpURL")).then((rsp) => {
28 | if (rsp.ok) {
29 | rsp.text().then((responseText) => {
30 | e.innerHTML = responseText;
31 | var myselfName = e.getAttribute("myselfName");
32 | var pluginName = rsp.headers.get("X-Plugin-Short-Name");
33 | if (myselfName != pluginName) {
34 | var from = rsp.headers.get("X-Plugin-From");
35 | if (from) {
36 | e.innerHTML += "
"+from+"
";
37 | }
38 | }
39 | layoutUpdateCallback.call();
40 | });
41 | } else {
42 | e.innerHTML = "ERROR: Failed to load help file: " + rsp.statusText;
43 | }
44 | });
45 | }});
46 |
47 | /**
48 | * Allows run Behavior when help is loaded.
49 | */
50 | layoutUpdateCallback.add(function() {
51 | document.querySelectorAll(".build-timeout-nested-help").forEach(function(e){Behaviour.applySubtree(e, true)});
52 | });
53 |
54 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-strategy.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout
26 |
27 | import jenkins.model.Jenkins
28 |
29 | st = namespace("jelly:stapler")
30 |
31 | def descriptor = Jenkins.instance.getDescriptorOrDie(BuildTimeoutWrapper.class)
32 |
33 | def myselfName = descriptor.plugin.shortName
34 |
35 | // help file for strategy itself.
36 | def strategyRawHelpFile = descriptor.getHelpFile("strategyRaw")
37 |
38 | if (strategyRawHelpFile != null) {
39 | div(
40 | class: "build-timeout-nested-help",
41 | helpURL: String.format("%s%s", rootURL, strategyRawHelpFile),
42 | myselfName: myselfName,
43 | ) {
44 | text("Loading...")
45 | }
46 | }
47 |
48 | dl() {
49 | descriptor.strategies.each() { d ->
50 | def helpFile = d.getHelpFile()
51 | dt(d.displayName)
52 | if (helpFile != null) {
53 | dd(
54 | class: "build-timeout-nested-help",
55 | helpURL: String.format("%s%s", rootURL, helpFile),
56 | myselfName: myselfName,
57 | ) {
58 | text("Loading...")
59 | }
60 | } else {
61 | dd("No help available.")
62 | }
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/impl/LikelyStuckTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.impl;
2 |
3 | import hudson.Extension;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.BuildListener;
6 | import hudson.model.Descriptor;
7 | import hudson.model.Executor;
8 | import hudson.model.Queue;
9 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
10 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
11 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
12 | import org.kohsuke.stapler.DataBoundConstructor;
13 |
14 | import edu.umd.cs.findbugs.annotations.NonNull;
15 | import java.io.IOException;
16 | import java.util.StringJoiner;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * Get the time considered it stuck.
21 | *
22 | * Return 10 times as much as eta if eta is available, else 24 hours.
23 | * @see Executor#isLikelyStuck()
24 | */
25 | public class LikelyStuckTimeOutStrategy extends BuildTimeOutStrategy {
26 |
27 |
28 | @DataBoundConstructor
29 | public LikelyStuckTimeOutStrategy() {
30 | }
31 |
32 | @Override
33 | public long getTimeOut(@NonNull AbstractBuild, ?> run, @NonNull BuildListener listener)
34 | throws InterruptedException, MacroEvaluationException, IOException {
35 | Executor executor = run.getExecutor();
36 | if (executor == null) {
37 | return TimeUnit.HOURS.toMillis(24);
38 | }
39 |
40 | Queue.Executable executable = executor.getCurrentExecutable();
41 | if (executable == null) {
42 | return TimeUnit.HOURS.toMillis(24);
43 | }
44 |
45 | long eta = executable.getEstimatedDuration();
46 | if (eta >= 0) {
47 | return eta * 10;
48 | } else {
49 | return TimeUnit.HOURS.toMillis(24);
50 | }
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return new StringJoiner(", ", LikelyStuckTimeOutStrategy.class.getSimpleName() + "[", "]")
56 | .add("preferred='10 x estimated duration'")
57 | .add("fallback='24 hours'")
58 | .toString();
59 | }
60 |
61 | public Descriptor getDescriptor() {
62 | return DESCRIPTOR;
63 | }
64 |
65 | @Extension
66 | public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
67 |
68 | public static class DescriptorImpl extends BuildTimeOutStrategyDescriptor {
69 |
70 | @Override
71 | public String getDisplayName() {
72 | return Messages.LikelyStuckTimeOutStrategy_DisplayName();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/BuildTimeOutOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout;
26 |
27 | import jenkins.model.Jenkins;
28 | import hudson.ExtensionPoint;
29 | import hudson.model.AbstractBuild;
30 | import hudson.model.Action;
31 | import hudson.model.BuildListener;
32 | import hudson.model.Describable;
33 |
34 | import edu.umd.cs.findbugs.annotations.NonNull;
35 |
36 | /**
37 | * Defines an operation performed when timeout occurs.
38 | * They are called "Timeout Actions", but the class is BuildTimeOutOperation
39 | * not to be confused with {@link Action}
40 | */
41 | public abstract class BuildTimeOutOperation
42 | implements ExtensionPoint, Describable {
43 |
44 | /**
45 | * Perform operation.
46 | *
47 | * @param build build timed out
48 | * @param listener build listener. can be used to print log.
49 | * @param effectiveTimeout timeout (milliseconds)
50 | * @return false not to run subsequent operations. It also mark the build as failure.
51 | */
52 | public abstract boolean perform(@NonNull AbstractBuild,?> build, @NonNull BuildListener listener, long effectiveTimeout);
53 |
54 | /**
55 | * @see hudson.model.Describable#getDescriptor()
56 | */
57 | public BuildTimeOutOperationDescriptor getDescriptor() {
58 | return (BuildTimeOutOperationDescriptor)Jenkins.getActiveInstance().getDescriptorOrDie(getClass());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.impl;
2 |
3 | import hudson.Extension;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.BuildListener;
6 | import hudson.model.Descriptor;
7 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
8 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
9 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
10 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
11 | import org.kohsuke.stapler.DataBoundConstructor;
12 |
13 | import edu.umd.cs.findbugs.annotations.NonNull;
14 | import java.io.IOException;
15 | import java.util.StringJoiner;
16 |
17 | /**
18 | * If the build took longer than {@code timeoutMinutes} amount of minutes, it will be terminated.
19 | */
20 | public class AbsoluteTimeOutStrategy extends BuildTimeOutStrategy {
21 |
22 | private final String timeoutMinutes;
23 |
24 | /**
25 | * @return minutes to timeout.
26 | */
27 | public String getTimeoutMinutes() {
28 | return timeoutMinutes;
29 | }
30 |
31 | @Deprecated
32 | public AbsoluteTimeOutStrategy(int timeoutMinutes) {
33 | this.timeoutMinutes = Integer.toString(Math.max((int) (BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS / MINUTES), timeoutMinutes));
34 | }
35 |
36 | @DataBoundConstructor
37 | public AbsoluteTimeOutStrategy(String timeoutMinutes) {
38 | this.timeoutMinutes = timeoutMinutes;
39 | }
40 |
41 | @Override
42 | public long getTimeOut(@NonNull AbstractBuild,?> build, @NonNull BuildListener listener)
43 | throws InterruptedException, MacroEvaluationException, IOException {
44 | return MINUTES * Math.max((int) (BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS / MINUTES), Integer.parseInt(
45 | expandAll(build, listener, getTimeoutMinutes())));
46 | }
47 |
48 | @Override
49 | public Descriptor getDescriptor() {
50 | return DESCRIPTOR;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return new StringJoiner(", ", AbsoluteTimeOutStrategy.class.getSimpleName() + "[", "]")
56 | .add("timeoutMinutes='" + timeoutMinutes + "'")
57 | .toString();
58 | }
59 |
60 | @Extension(ordinal=100) // This is displayed at the top as the default
61 | public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
62 |
63 | public static class DescriptorImpl extends BuildTimeOutStrategyDescriptor {
64 |
65 | @Override
66 | public String getDisplayName() {
67 | return Messages.AbsoluteTimeOutStrategy_DisplayName();
68 | }
69 |
70 | @Override
71 | public boolean isApplicableAsBuildStep() {
72 | return true;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/build_timeout/impl/Messages_ja.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2014 IKEDA Yasuyuki
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | AbsoluteTimeOutStrategy.DisplayName=\u4e00\u5b9a\u306e\u7d4c\u904e\u6642\u9593
24 | ElasticTimeOutStrategy.DisplayName=\u904e\u53bb\u306e\u30d3\u30eb\u30c9\u6642\u9593\u3068\u306e\u6bd4\u8f03
25 | LikelyStuckTimeOutStrategy.DisplayName=\u30d3\u30eb\u30c9\u306e\u4e88\u6e2c\u6700\u5927\u6642\u9593\u3068\u306e\u6bd4\u8f03
26 | NoActivityTimeOutStrategy.DisplayName=\u6700\u5f8c\u306e\u30ed\u30b0\u306e\u51fa\u529b\u304b\u3089\u306e\u7d4c\u904e\u6642\u9593
27 | DeadlineTimeOutStrategy.DisplayName=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3
28 | DeadlineTimeOutStrategy.ImmediatelyTerminate=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3\u76f4\u5f8c\u306e\u5373\u6642\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u6642\u9593\u5185\u3067\u3059 ({0} + {1} \u5206)\u3002 \u305f\u3060\u3061\u306b\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u51e6\u7406\u3092\u884c\u3044\u307e\u3059\u3002
29 | DeadlineTimeOutStrategy.NextDeadline=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3: {0}
30 | DeadlineTimeOutStrategy.InvalidDeadlineFormat=\u6307\u5b9a\u306e\u6642\u523b\u306e\u30d5\u30a9\u30fc\u30de\u30c3\u30c8 ''{0}'' \u304c\u4e0d\u6b63\u3067\u3059\u300224 \u6642\u9593\u8868\u8a18\u3067 HH:MM \u307e\u305f\u306f HH:MM:SS \u306e\u5f62\u5f0f\u3067\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002
31 | DeadlineTimeOutStrategy.DeadlineFormatWithMacros=\u30c7\u30c3\u30c9\u30e9\u30a4\u30f3\u304c\u5909\u6570\u3092\u4f7f\u7528\u3057\u3066\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002\u5b9f\u884c\u6642\u306b\u5909\u6570\u5c55\u958b\u5f8c\u306e\u5024\u304c 24 \u6642\u9593\u8868\u8a18\u3067 HH:MM \u3082\u3057\u304f\u306f HH:MM:SS \u8868\u8a18\u306b\u306a\u3063\u3066\u3044\u306a\u3044\u5834\u5408\u3001\u30d3\u30eb\u30c9\u306b\u5931\u6557\u3057\u307e\u3059\u3002
32 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/TimeOutTask.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import hudson.model.AbstractBuild;
4 | import hudson.model.BuildListener;
5 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
6 |
7 | import java.time.Duration;
8 | import java.util.List;
9 | import java.util.logging.Level;
10 | import java.util.logging.Logger;
11 |
12 | public class TimeOutTask implements Runnable {
13 | private static final Logger log = Logger.getLogger(TimeOutTask.class.getName());
14 | private final TimeOutProvider timeOutProvider;
15 | private final AbstractBuild, ?> build;
16 | private final BuildListener listener;
17 | private final Duration duration;
18 |
19 | private TimeOutTask(TimeOutProvider timeOutProvider, AbstractBuild, ?> build, BuildListener listener, Duration duration) {
20 | this.timeOutProvider = timeOutProvider;
21 | this.build = build;
22 | this.listener = listener;
23 | this.duration = duration;
24 | }
25 |
26 | @Override
27 | public void run() {
28 | List operations = timeOutProvider.getOperations();
29 | for (BuildTimeOutOperation operation : operations) {
30 | try {
31 | boolean succeeded = operation.perform(build, listener, duration.toMillis());
32 | if (!succeeded) {
33 | log.info(() -> String.format(
34 | "%s failed to perform global time out %s after %d minutes - no further operations will be run",
35 | build.getExternalizableId(),
36 | operation.getClass().getSimpleName(),
37 | duration.toMinutes()
38 | ));
39 | return;
40 | }
41 | listener.getLogger().println("[build-timeout] Global time out activated");
42 | log.fine(() -> String.format(
43 | "%s successfully performed global time out %s after %d minutes",
44 | build.getExternalizableId(),
45 | operation.getClass().getSimpleName(),
46 | duration.toMinutes()));
47 | } catch (RuntimeException e) {
48 | log.log(Level.WARNING, e, () -> String.format(
49 | "%s failed to perform global time out %s after %d minutes - no further operations will be run",
50 | build.getExternalizableId(),
51 | operation.getClass().getSimpleName(),
52 | duration.toMinutes()));
53 | return;
54 | }
55 | }
56 | }
57 |
58 | public static TimeOutTask create(TimeOutProvider timeOutProvider, AbstractBuild,?> build, BuildListener listener, Duration duration) {
59 | return new TimeOutTask(timeOutProvider, build, listener, duration);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/BuildTimeOutOperationDescriptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | import jenkins.model.Jenkins;
31 | import hudson.model.AbstractProject;
32 | import hudson.model.Descriptor;
33 | import hudson.tasks.BuildStepDescriptor;
34 |
35 | /**
36 | * Descriptor for {@link BuildTimeOutOperation}
37 | */
38 | public abstract class BuildTimeOutOperationDescriptor extends Descriptor {
39 | /**
40 | * Returns true if this task is applicable to the given project.
41 | *
42 | * Override this to restrict project types this action can be applied.
43 | *
44 | * @return
45 | * true to allow user to configure this timeout action to given project.
46 | * @see BuildStepDescriptor#isApplicable(Class)
47 | */
48 | public boolean isApplicable(Class extends AbstractProject,?>> jobType) {
49 | return true;
50 | }
51 |
52 | public static List all(Class extends AbstractProject,?>> jobType) {
53 | List alldescs = Jenkins.getActiveInstance().getDescriptorList(BuildTimeOutOperation.class);
54 | List descs = new ArrayList<>();
55 | for (BuildTimeOutOperationDescriptor d: alldescs) {
56 | if (jobType == null || d.isApplicable(jobType)) {
57 | descs.add(d);
58 | }
59 | }
60 | return descs;
61 | }
62 |
63 | public static List all() {
64 | return all(null);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = Build Timeout Plugin
2 |
3 | This plugin allows you to automatically terminate a build if it's taking too long.
4 |
5 | This plugin isn't applicable to pipelines.
6 |
7 | Use the https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#timeout-enforce-time-limit[`+timeout+` step in workflow-basic-steps] instead.
8 |
9 | == Instructions for the user
10 |
11 | === Global configuration
12 |
13 | Go to `Manage Jenkins` and then `Configure System`. Under the item `Global Build Time Out` you can activate a global
14 | timeout which will be applied to any job. Choose your timeout strategy, the duration and add actions which should be
15 | executed at timeout.
16 |
17 | In addition, the option can be activated that individual jobs can overwrite the global timeout if they
18 | provide a corresponding build step.
19 |
20 | image::doc/global-config.png[]
21 |
22 | Note that sometimes if a project is not of the `hudson.model.Project` type,
23 | then the individual jobs would not be allowed to overwrite the global timeout.
24 |
25 | === Build environment
26 |
27 | Alternatively, the timeout can be specified in the build environment of a job.
28 | To do this, click `Configure` in the job view and in the build environment section, select the item
29 | `Terminate a build if it's stuck`.
30 |
31 | image::doc/build-environment.png[]
32 |
33 | Because Java only allows threads to be interrupted at a set of fixed locations, depending on how a build hangs, the abort operation might not take effect. For example,
34 |
35 | * if Jenkins is waiting for child processes to complete, it can abort right away.
36 | * if Jenkins is stuck in an infinite loop, it can never be aborted.
37 | * if Jenkins is doing a network or file I/O within the Java VM (such as lengthy file copy or SVN update), it cannot be aborted.
38 |
39 | So if you think the build timeout isn't taking effect, our default assumption is that the build is hanging at the place that cannot be interrupted. If you suspect otherwise, please https://wiki.jenkins-ci.org/display/JENKINS/Build+is+hanging[obtain the thread dump] and report it.
40 |
41 | === Build step
42 |
43 | Add a new step `Run with timeout` at the section `Build`, add the timeout strategy and duration, add some actions and
44 | the build step you want to execute within the timout step.
45 |
46 | image::doc/build-step.png[]
47 |
48 | == For developers
49 |
50 | If you are interested in contributing,
51 | please pay attention to the below steps:
52 |
53 | === To test
54 |
55 | [source,shell]
56 | ----
57 | mvn verify
58 | ----
59 |
60 | === To build
61 | [source,shell]
62 | ----
63 | mvn hpi:run
64 | ----
65 |
66 | For newcomers,
67 | please see guide at https://www.jenkins.io/participate/[] for more information about how to participate and contribute.
68 |
69 | == Time-out actions with notes
70 |
71 | [cols=",",options="header",]
72 | |===
73 | |Time-out action |Note
74 | |Abort and restart the build |Installing https://plugins.jenkins.io/naginator[Naginator Plugin] enables this action
75 | |===
76 |
77 | include::CHANGELOG.adoc[]
78 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/operations/FailOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import static java.util.concurrent.TimeUnit.MILLISECONDS;
28 | import static java.util.concurrent.TimeUnit.MINUTES;
29 |
30 | import org.kohsuke.stapler.DataBoundConstructor;
31 |
32 | import hudson.Extension;
33 | import hudson.model.AbstractBuild;
34 | import hudson.model.BuildListener;
35 | import hudson.model.Executor;
36 | import hudson.model.Result;
37 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
38 | import hudson.plugins.build_timeout.BuildTimeOutOperationDescriptor;
39 |
40 | /**
41 | * Fail the build.
42 | */
43 | public class FailOperation extends BuildTimeOutOperation {
44 | @DataBoundConstructor
45 | public FailOperation() {
46 | }
47 |
48 | /**
49 | * @see hudson.plugins.build_timeout.BuildTimeOutOperation#perform(hudson.model.AbstractBuild, hudson.model.BuildListener, long)
50 | */
51 | @Override
52 | public boolean perform(AbstractBuild, ?> build, BuildListener listener, long effectiveTimeout) {
53 | long effectiveTimeoutMinutes = MINUTES.convert(effectiveTimeout,MILLISECONDS);
54 | // Use messages in hudson.plugins.build_timeout.Messages for historical reason.
55 | listener.getLogger().println(hudson.plugins.build_timeout.Messages.Timeout_Message(
56 | effectiveTimeoutMinutes,
57 | hudson.plugins.build_timeout.Messages.Timeout_Failed())
58 | );
59 |
60 | Executor e = build.getExecutor();
61 | if (e != null) {
62 | e.interrupt(Result.FAILURE);
63 | }
64 |
65 | return true;
66 | }
67 |
68 | @Extension(ordinal=50) // should be located at the second.
69 | public static class DescriptorImpl extends BuildTimeOutOperationDescriptor {
70 | @Override
71 | public String getDisplayName() {
72 | return Messages.FailOperation_DisplayName();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/operations/AbortOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import static java.util.concurrent.TimeUnit.MILLISECONDS;
28 | import static java.util.concurrent.TimeUnit.MINUTES;
29 |
30 | import org.kohsuke.stapler.DataBoundConstructor;
31 |
32 | import hudson.Extension;
33 | import hudson.model.AbstractBuild;
34 | import hudson.model.BuildListener;
35 | import hudson.model.Executor;
36 | import hudson.model.Result;
37 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
38 | import hudson.plugins.build_timeout.BuildTimeOutOperationDescriptor;
39 |
40 | /**
41 | * Abort the build.
42 | */
43 | public class AbortOperation extends BuildTimeOutOperation {
44 | @DataBoundConstructor
45 | public AbortOperation(){
46 | }
47 |
48 | /**
49 | * @param build
50 | * @param listener
51 | * @param effectiveTimeout
52 | * @return
53 | * @see hudson.plugins.build_timeout.BuildTimeOutOperation#perform(hudson.model.AbstractBuild, hudson.model.BuildListener, long)
54 | */
55 | @Override
56 | public boolean perform(AbstractBuild, ?> build, BuildListener listener, long effectiveTimeout) {
57 | long effectiveTimeoutMinutes = MINUTES.convert(effectiveTimeout,MILLISECONDS);
58 | // Use messages in hudson.plugins.build_timeout.Messages for historical reason.
59 | listener.getLogger().println(hudson.plugins.build_timeout.Messages.Timeout_Message(
60 | effectiveTimeoutMinutes,
61 | hudson.plugins.build_timeout.Messages.Timeout_Aborted())
62 | );
63 |
64 | Executor e = build.getExecutor();
65 | if (e != null) {
66 | e.interrupt(Result.ABORTED);
67 | }
68 |
69 | return true;
70 | }
71 |
72 | @Extension(ordinal=100) // should be located at the top.
73 | public static class DescriptorImpl extends BuildTimeOutOperationDescriptor {
74 | @Override
75 | public String getDisplayName() {
76 | return Messages.AbortOperation_DisplayName();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/BuildStepWithTimeoutTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout;
2 |
3 | import hudson.model.Cause;
4 | import hudson.model.FreeStyleBuild;
5 | import hudson.model.FreeStyleProject;
6 | import hudson.model.Result;
7 | import hudson.plugins.build_timeout.operations.AbortOperation;
8 | import hudson.plugins.build_timeout.operations.FailOperation;
9 | import hudson.tasks.Builder;
10 | import org.junit.jupiter.api.BeforeEach;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import org.jvnet.hudson.test.JenkinsRule;
14 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
15 |
16 | import java.io.IOException;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | @WithJenkins
21 | class BuildStepWithTimeoutTest {
22 |
23 | private static final long TINY_DELAY = 100L;
24 | private static final long HUGE_DELAY = 5000L;
25 |
26 | @BeforeEach
27 | void before() {
28 | // this allows timeout shorter than 3 minutes.
29 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = 100;
30 | }
31 |
32 | @Test
33 | void timeoutWasNotTriggered(JenkinsRule j) throws Exception {
34 | final FreeStyleProject project = createProjectWithBuildStepWithTimeout(TINY_DELAY, null, j);
35 |
36 | final FreeStyleBuild build = project.scheduleBuild2(0, new Cause.UserIdCause()).get();
37 |
38 | j.assertBuildStatusSuccess(build);
39 | j.assertLogContains(FakeBuildStep.FAKE_BUILD_STEP_OUTPUT, build);
40 | }
41 |
42 | @Test
43 | void timeoutWasTriggeredWithoutAction(JenkinsRule j) throws Exception {
44 | final FreeStyleProject project = createProjectWithBuildStepWithTimeout(HUGE_DELAY, null, j);
45 |
46 | final FreeStyleBuild build = project.scheduleBuild2(0, new Cause.UserIdCause()).get();
47 |
48 | j.assertBuildStatus(Result.ABORTED, build);
49 | j.assertLogNotContains(FakeBuildStep.FAKE_BUILD_STEP_OUTPUT, build);
50 | }
51 |
52 | @Test
53 | void timeoutWasTriggeredWithAbortOperation(JenkinsRule j) throws Exception {
54 | final FreeStyleProject project = createProjectWithBuildStepWithTimeout(HUGE_DELAY, new AbortOperation(), j);
55 |
56 | final FreeStyleBuild build = project.scheduleBuild2(0, new Cause.UserIdCause()).get();
57 |
58 | j.assertBuildStatus(Result.ABORTED, build);
59 | j.assertLogNotContains(FakeBuildStep.FAKE_BUILD_STEP_OUTPUT, build);
60 | }
61 |
62 | @Test
63 | void timeoutWasTriggeredWithFailOperation(JenkinsRule j) throws Exception {
64 | final FreeStyleProject project = createProjectWithBuildStepWithTimeout(HUGE_DELAY, new FailOperation(), j);
65 |
66 | final FreeStyleBuild build = project.scheduleBuild2(0, new Cause.UserIdCause()).get();
67 |
68 | j.assertBuildStatus(Result.FAILURE, build);
69 | j.assertLogNotContains(FakeBuildStep.FAKE_BUILD_STEP_OUTPUT, build);
70 | }
71 |
72 | private FreeStyleProject createProjectWithBuildStepWithTimeout(long delay, BuildTimeOutOperation operation, JenkinsRule j) throws IOException {
73 | final FreeStyleProject project = j.createFreeStyleProject();
74 | final List operations;
75 |
76 | if (operation!=null) {
77 | operations = new ArrayList<>();
78 | operations.add(operation);
79 | } else {
80 | operations = null;
81 | }
82 |
83 | final Builder step = new BuildStepWithTimeout(new FakeBuildStep(delay),
84 | new QuickBuildTimeOutStrategy(500), operations);
85 |
86 | project.getBuildersList().add(step);
87 |
88 | return project;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/operations/WriteDescriptionOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import static java.util.concurrent.TimeUnit.MILLISECONDS;
28 | import static java.util.concurrent.TimeUnit.MINUTES;
29 |
30 | import java.io.IOException;
31 | import java.text.MessageFormat;
32 |
33 | import org.kohsuke.stapler.DataBoundConstructor;
34 |
35 | import hudson.Extension;
36 | import hudson.model.AbstractBuild;
37 | import hudson.model.BuildListener;
38 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
39 | import hudson.plugins.build_timeout.BuildTimeOutOperationDescriptor;
40 |
41 | /**
42 | * Set Description for the build timed out.
43 | */
44 | public class WriteDescriptionOperation extends BuildTimeOutOperation {
45 | private final String description;
46 |
47 | /**
48 | * @return description to set.
49 | */
50 | public String getDescription() {
51 | return description;
52 | }
53 |
54 | @DataBoundConstructor
55 | public WriteDescriptionOperation(String description) {
56 | this.description = description;
57 | }
58 |
59 | @Override
60 | public boolean perform(AbstractBuild, ?> build, BuildListener listener, long effectiveTimeout) {
61 | // timed out
62 | long effectiveTimeoutMinutes = MINUTES.convert(effectiveTimeout,MILLISECONDS);
63 | String msg = getDescription();
64 | try {
65 | msg = build.getEnvironment(listener).expand(msg);
66 | } catch (IOException | InterruptedException e) {
67 | listener.getLogger().println(String.format("failed to expand string: %s", msg));
68 | e.printStackTrace(listener.getLogger());
69 | }
70 |
71 | msg = MessageFormat.format(msg, effectiveTimeoutMinutes);
72 |
73 | try {
74 | build.setDescription(msg);
75 | } catch (IOException e) {
76 | listener.getLogger().println("failed to write to the build description!");
77 | e.printStackTrace(listener.getLogger());
78 | }
79 |
80 | return true;
81 | }
82 |
83 | @Extension
84 | public static class DescriptorImpl extends BuildTimeOutOperationDescriptor {
85 | @Override
86 | public String getDisplayName() {
87 | return Messages.WriteDescriptionOperation_DisplayName();
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/global/TimeOutTaskTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import com.google.common.collect.Lists;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.BuildListener;
6 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
7 | import org.junit.jupiter.api.BeforeEach;
8 | import org.junit.jupiter.api.Test;
9 | import org.junit.jupiter.api.extension.ExtendWith;
10 |
11 | import org.mockito.Answers;
12 | import org.mockito.Mock;
13 | import org.mockito.junit.jupiter.MockitoExtension;
14 | import edu.umd.cs.findbugs.annotations.NonNull;
15 | import java.time.Duration;
16 |
17 | import static org.junit.jupiter.api.Assertions.assertFalse;
18 | import static org.junit.jupiter.api.Assertions.assertTrue;
19 | import static org.mockito.BDDMockito.given;
20 |
21 | @ExtendWith(MockitoExtension.class)
22 | class TimeOutTaskTest {
23 | @Mock
24 | private TimeOutProvider timeOutProvider;
25 | @Mock
26 | private AbstractBuild, ?> build;
27 | @Mock(answer = Answers.RETURNS_DEEP_STUBS)
28 | private BuildListener listener;
29 | private TimeOutTask task;
30 |
31 | @BeforeEach
32 | void setup() {
33 | task = TimeOutTask.create(timeOutProvider, build, listener, Duration.ofMillis(1));
34 | }
35 |
36 | @Test
37 | void shouldCallAllOperations() {
38 | TestOp one = new TestOp();
39 | TestOp two = new TestOp();
40 | given(timeOutProvider.getOperations()).willReturn(Lists.newArrayList(one, two));
41 |
42 | task.run();
43 |
44 | assertTrue(one.performed);
45 | assertTrue(two.performed);
46 | }
47 |
48 | @Test
49 | void shouldStopAtFirstFailure() {
50 | TestOp one = new TestOp();
51 | FailsOp two = new FailsOp();
52 | TestOp three = new TestOp();
53 | given(timeOutProvider.getOperations()).willReturn(Lists.newArrayList(one, two, three));
54 |
55 | task.run();
56 |
57 | assertTrue(one.performed);
58 | assertTrue(two.performed);
59 | assertFalse(three.performed);
60 | }
61 |
62 | @Test
63 | void shouldStopAtFirstException() {
64 | TestOp one = new TestOp();
65 | ThrowsOp two = new ThrowsOp();
66 | TestOp three = new TestOp();
67 | given(timeOutProvider.getOperations()).willReturn(Lists.newArrayList(one, two, three));
68 |
69 | task.run();
70 |
71 | assertTrue(one.performed);
72 | assertTrue(two.performed);
73 | assertFalse(three.performed);
74 | }
75 |
76 | private static class TestOp extends BuildTimeOutOperation {
77 | boolean performed = false;
78 |
79 | @Override
80 | public boolean perform(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener, long effectiveTimeout) {
81 | performed = true;
82 | return true;
83 | }
84 | }
85 |
86 | private static class FailsOp extends BuildTimeOutOperation {
87 | boolean performed = false;
88 |
89 | @Override
90 | public boolean perform(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener, long effectiveTimeout) {
91 | performed = true;
92 | return false;
93 | }
94 | }
95 |
96 | private static class ThrowsOp extends BuildTimeOutOperation {
97 | boolean performed = false;
98 |
99 | @Override
100 | public boolean perform(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener, long effectiveTimeout) {
101 | performed = true;
102 | throw new RuntimeException("bad");
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/BuildTimeOutUtility.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout;
26 |
27 | import hudson.model.Describable;
28 | import hudson.model.Descriptor;
29 | import hudson.model.Descriptor.FormException;
30 | import jenkins.model.Jenkins;
31 | import net.sf.json.JSONObject;
32 |
33 | import org.kohsuke.stapler.DataBoundConstructor;
34 | import org.kohsuke.stapler.StaplerRequest2;
35 |
36 | public class BuildTimeOutUtility {
37 | /**
38 | * Construct an object from parameters input by a user.
39 | *
40 | * Not using {@link DataBoundConstructor},
41 | * but using {@link Descriptor#newInstance(StaplerRequest2, JSONObject)}.
42 | */
43 | public static T bindJSONWithDescriptor(StaplerRequest2 req, JSONObject formData, String fieldName, Class expectedClazz)
44 | throws hudson.model.Descriptor.FormException {
45 | formData = formData.getJSONObject(fieldName);
46 | if (formData == null || formData.isNullObject()) {
47 | return null;
48 | }
49 | String clazzName = formData.optString("$class", null);
50 | if (clazzName == null) {
51 | // Fall back on the legacy stapler-class attribute.
52 | clazzName = formData.optString("stapler-class", null);
53 | }
54 | if (clazzName == null) {
55 | throw new FormException("No $class or stapler-class is specified", fieldName);
56 | }
57 | try {
58 | @SuppressWarnings("unchecked")
59 | Class extends Describable>> clazz = (Class extends Describable>>)Jenkins.getActiveInstance().getPluginManager().uberClassLoader.loadClass(clazzName);
60 | Descriptor> d = Jenkins.getActiveInstance().getDescriptorOrDie(clazz);
61 | @SuppressWarnings("unchecked")
62 | T ret = (T)d.newInstance(req, formData);
63 | return ret;
64 | } catch(ClassNotFoundException e) {
65 | throw new FormException(
66 | String.format("Failed to instantiate: class not found %s", clazzName),
67 | e,
68 | fieldName
69 | );
70 | } catch(ClassCastException e) {
71 | throw new FormException(
72 | String.format("Failed to instantiate: instantiated as %s but expected %s", clazzName, expectedClazz.getName()),
73 | e,
74 | fieldName
75 | );
76 | }
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.impl;
26 |
27 | import java.util.Arrays;
28 |
29 | import hudson.model.ParametersDefinitionProperty;
30 | import hudson.model.Result;
31 | import hudson.model.Cause;
32 | import hudson.model.FreeStyleProject;
33 | import hudson.model.ParametersAction;
34 | import hudson.model.StringParameterDefinition;
35 | import hudson.model.StringParameterValue;
36 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
37 | import hudson.plugins.build_timeout.operations.AbortOperation;
38 |
39 | import org.junit.jupiter.api.AfterEach;
40 | import org.junit.jupiter.api.BeforeEach;
41 | import org.junit.jupiter.api.Test;
42 |
43 | import org.jvnet.hudson.test.JenkinsRule;
44 | import org.jvnet.hudson.test.SleepBuilder;
45 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
46 |
47 | /**
48 | * Tests for {@link AbsoluteTimeOutStrategy}.
49 | * Many tests for {@link AbsoluteTimeOutStrategy} are also in {@see BuildTimeoutWrapperIntegrationTest}
50 | */
51 | @WithJenkins
52 | class AbsoluteTimeOutStrategyTest {
53 |
54 | private long origTimeout = 0;
55 |
56 | @BeforeEach
57 | void before() {
58 | // this allows timeout shorter than 3 minutes.
59 | origTimeout = BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS;
60 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = 1000;
61 | }
62 |
63 | @AfterEach
64 | void after() {
65 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = origTimeout;
66 | }
67 |
68 | @Test
69 | void configurationWithParameter(JenkinsRule j) throws Exception {
70 | FreeStyleProject p = j.createFreeStyleProject();
71 | // needed since Jenkins 2.3
72 | p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("TIMEOUT", null)));
73 | p.getBuildWrappersList().add(
74 | new BuildTimeoutWrapper(
75 | new AbsoluteTimeOutStrategy("${TIMEOUT}"),
76 | Arrays.asList(new AbortOperation()),
77 | null
78 | )
79 | );
80 | p.getBuildersList().add(new SleepBuilder(5000));
81 |
82 | // If called with TIMEOUT=1, the build succeeds.
83 | j.assertBuildStatus(Result.SUCCESS, p.scheduleBuild2(
84 | 0,
85 | new Cause.UserCause(),
86 | new ParametersAction(new StringParameterValue("TIMEOUT", "1"))
87 | ).get());
88 |
89 | // If called with TIMEOUT=0, the build is aborted immediately.
90 | j.assertBuildStatus(Result.ABORTED, p.scheduleBuild2(
91 | 0,
92 | new Cause.UserCause(),
93 | new ParametersAction(new StringParameterValue("TIMEOUT", "0"))
94 | ).get());
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.jenkins-ci.plugins
7 | plugin
8 | 5.28
9 |
10 |
11 |
12 | build-timeout
13 | ${revision}${changelist}
14 | hpi
15 |
16 | Build Timeout
17 | To terminate a build if it is taking too long
18 | https://github.com/jenkinsci/${project.artifactId}-plugin
19 |
20 |
21 | The MIT License (MIT)
22 | https://opensource.org/licenses/MIT
23 | repo
24 |
25 |
26 |
27 |
28 | scm:git:https://github.com/${gitHubRepo}.git
29 | scm:git:git@github.com:${gitHubRepo}.git
30 | ${scmTag}
31 | https://github.com/${gitHubRepo}
32 |
33 |
34 |
35 | 1.39
36 | -SNAPSHOT
37 |
38 | 2.504
39 | ${jenkins.baseline}.1
40 | jenkinsci/${project.artifactId}-plugin
41 | false
42 |
43 |
44 |
45 |
46 |
47 | org.apache.maven.plugins
48 | maven-compiler-plugin
49 |
50 |
51 |
52 | true
53 | true
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | io.jenkins.tools.bom
65 | bom-${jenkins.baseline}.x
66 | 5388.v3ea_2e00a_719a_
67 | pom
68 | import
69 |
70 |
71 |
72 |
73 |
74 |
75 | io.jenkins.plugins
76 | json-path-api
77 |
78 |
79 | org.jenkins-ci.plugins
80 | token-macro
81 |
82 |
83 | org.jenkins-ci.plugins
84 | naginator
85 | 1.530.vb_6d120f250b_1
86 | true
87 |
88 |
89 | org.mockito
90 | mockito-core
91 | test
92 |
93 |
94 | org.mockito
95 | mockito-junit-jupiter
96 | test
97 |
98 |
99 |
100 |
101 |
102 | repo.jenkins-ci.org
103 | https://repo.jenkins-ci.org/public/
104 |
105 |
106 |
107 |
108 | repo.jenkins-ci.org
109 | https://repo.jenkins-ci.org/public/
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/BuildTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout;
2 |
3 | import java.util.logging.Level;
4 | import java.util.logging.Logger;
5 |
6 | import hudson.model.*;
7 | import jenkins.model.Jenkins;
8 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
9 | import org.jenkinsci.plugins.tokenmacro.TokenMacro;
10 |
11 | import edu.umd.cs.findbugs.annotations.NonNull;
12 | import java.io.IOException;
13 |
14 | /**
15 | * @author Nicolas De Loof
16 | */
17 | public abstract class BuildTimeOutStrategy implements Describable {
18 |
19 | public static final long MINUTES = 60*1000L;
20 | public static final Logger LOG = Logger.getLogger(BuildTimeOutStrategy.class.getName());
21 |
22 | /**
23 | * Define the delay (in milliseconds) to wait for the build to complete before interrupting.
24 | * @param run
25 | * @deprecated override {@link #getTimeOut(hudson.model.AbstractBuild, hudson.model.BuildListener)} instead.
26 | */
27 | @Deprecated
28 | public long getTimeOut(@NonNull Run run) {
29 | throw new UnsupportedOperationException("Implementation required");
30 | }
31 |
32 | /**
33 | * Define the delay (in milliseconds) to wait for the build to complete before interrupting.
34 | * @param build the build
35 | * @param listener the build listener
36 | */
37 | @SuppressWarnings("deprecation")
38 | public long getTimeOut(@NonNull AbstractBuild,?> build, @NonNull BuildListener listener)
39 | throws InterruptedException, MacroEvaluationException, IOException {
40 | // call through to the old method.
41 | return getTimeOut(build);
42 | }
43 |
44 | /**
45 | * Called when some output to console.
46 | * Override this to capture the activity.
47 | *
48 | * @param build
49 | * @param b output character.
50 | *
51 | * @deprecated use {@link #onWrite(AbstractBuild, byte[], int)}
52 | *
53 | */
54 | @Deprecated
55 | public void onWrite(AbstractBuild,?> build, int b) {}
56 |
57 | /**
58 | * Called when some output to console.
59 | * Override this to capture the activity.
60 | *
61 | * @param build
62 | * @param b output characters.
63 | * @param length length of b to output
64 | *
65 | */
66 | public void onWrite(AbstractBuild,?> build, byte b[], int length) {
67 | for(int i = 0; i < length; ++i) {
68 | onWrite(build, b[i]);
69 | }
70 | }
71 |
72 | /**
73 | * Decides whether to call {@link #onWrite(AbstractBuild, byte[], int)}
74 | *
75 | * For performance reason, {@link #onWrite(AbstractBuild, byte[], int)} is called
76 | * only when subclass overrides it.
77 | *
78 | * @return true to call {@link #onWrite(AbstractBuild, byte[], int)}
79 | */
80 | public boolean wantsCaptureLog() {
81 | try {
82 | Class> classOfOnWrite = getClass().getMethod("onWrite", AbstractBuild.class, int.class).getDeclaringClass();
83 | Class> classOfNewOnWrite = getClass().getMethod("onWrite", AbstractBuild.class, byte[].class, int.class).getDeclaringClass();
84 | return !BuildTimeOutStrategy.class.equals(classOfOnWrite) || !BuildTimeOutStrategy.class.equals(classOfNewOnWrite);
85 | } catch(SecurityException|NoSuchMethodException e) {
86 | LOG.log(Level.WARNING, "Unexpected exception in build-timeout-plugin", e);
87 | return false;
88 | }
89 | }
90 |
91 | /**
92 | * @return
93 | * @see hudson.model.Describable#getDescriptor()
94 | */
95 | @SuppressWarnings("unchecked")
96 | public Descriptor getDescriptor() {
97 | return Jenkins.getActiveInstance().getDescriptorOrDie(getClass());
98 | }
99 |
100 | protected final String expandAll(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener, @NonNull String string)
101 | throws MacroEvaluationException, IOException, InterruptedException {
102 | return hasMacros(string) ? TokenMacro.expandAll(build, listener, string) : string;
103 | }
104 |
105 | protected final static boolean hasMacros(@NonNull String value) {
106 | return value.contains("${");
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.impl;
26 |
27 | import hudson.model.BuildListener;
28 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
29 | import org.kohsuke.stapler.DataBoundConstructor;
30 |
31 | import hudson.Extension;
32 | import hudson.model.AbstractBuild;
33 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
34 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
35 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
36 |
37 | import edu.umd.cs.findbugs.annotations.NonNull;
38 | import java.io.IOException;
39 | import java.util.StringJoiner;
40 |
41 | /**
42 | * Timeout when specified time passed since the last output.
43 | */
44 | public class NoActivityTimeOutStrategy extends BuildTimeOutStrategy {
45 | @Deprecated
46 | private transient long timeout;
47 |
48 | private final String timeoutSecondsString;
49 |
50 | /**
51 | * @deprecated use {@link NoActivityTimeOutStrategy#getTimeoutSecondsString()} instead.
52 | */
53 | @Deprecated
54 | public long getTimeoutSeconds() {
55 | try {
56 | return Long.parseLong(timeoutSecondsString);
57 | } catch(NumberFormatException e) {
58 | return 0L;
59 | }
60 | }
61 |
62 | public String getTimeoutSecondsString()
63 | {
64 | return timeoutSecondsString;
65 | }
66 |
67 | private Object readResolve() {
68 | if(timeoutSecondsString == null) {
69 | return new NoActivityTimeOutStrategy(this.timeout / 1000L);
70 | }
71 |
72 | return this;
73 | }
74 |
75 | @DataBoundConstructor
76 | public NoActivityTimeOutStrategy(String timeoutSecondsString) {
77 | this.timeoutSecondsString = timeoutSecondsString;
78 | }
79 |
80 | @Deprecated
81 | public NoActivityTimeOutStrategy(long timeoutSeconds) {
82 | this(Long.toString(timeoutSeconds));
83 | }
84 |
85 | @Override
86 | public long getTimeOut(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener)
87 | throws InterruptedException, MacroEvaluationException, IOException {
88 | return Long.parseLong(expandAll(build, listener, getTimeoutSecondsString())) * 1000L;
89 | }
90 |
91 | @Override
92 | public void onWrite(AbstractBuild,?> build, byte b[], int length) {
93 | BuildTimeoutWrapper.EnvironmentImpl env = build.getEnvironments().get(BuildTimeoutWrapper.EnvironmentImpl.class);
94 | if (env != null) {
95 | env.rescheduleIfScheduled();
96 | }
97 | }
98 |
99 | @Override
100 | public String toString() {
101 | return new StringJoiner(", ", NoActivityTimeOutStrategy.class.getSimpleName() + "[", "]")
102 | .add("(deprecated)timeout=" + timeout)
103 | .add("timeoutSecondsString='" + timeoutSecondsString + "'")
104 | .toString();
105 | }
106 |
107 | @Extension
108 | public static class DescriptorImpl extends BuildTimeOutStrategyDescriptor {
109 | @Override
110 | public String getDisplayName() {
111 | return Messages.NoActivityTimeOutStrategy_DisplayName();
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategyTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.impl;
2 |
3 | import hudson.model.FreeStyleBuild;
4 | import hudson.model.FreeStyleProject;
5 | import hudson.model.Result;
6 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
7 | import org.junit.jupiter.api.Test;
8 | import org.junit.jupiter.api.io.TempDir;
9 | import org.mockito.Mockito;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.nio.file.Path;
14 |
15 | import static hudson.model.Result.SUCCESS;
16 | import static hudson.plugins.build_timeout.BuildTimeOutStrategy.MINUTES;
17 | import static org.junit.jupiter.api.Assertions.assertEquals;
18 |
19 | /**
20 | * @author Nicolas De Loof
21 | */
22 | class ElasticTimeOutStrategyTest {
23 |
24 | @TempDir
25 | private Path directory;
26 |
27 | @Test
28 | void percentageWithOneBuild() throws Exception {
29 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy(200, 60, 3);
30 |
31 | Build b = new Build(new Build(60 * MINUTES, SUCCESS));
32 |
33 | assertEquals(120 * MINUTES, strategy.getTimeOut(b,null),"Timeout should be 200% of 60");
34 | }
35 |
36 | @Test
37 | void percentageWithTwoBuilds() throws Exception {
38 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy(200, 60, 3);
39 |
40 | Build b = new Build(new Build(20 * MINUTES, SUCCESS, new Build(40 * MINUTES, SUCCESS)));
41 |
42 | assertEquals(60 * MINUTES, strategy.getTimeOut(b,null),"Timeout should be 200% of the average of 20 and 40");
43 | }
44 |
45 | @Test
46 | void percentageWithNoBuilds() throws Exception {
47 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy(200, 90, 3);
48 |
49 | Build b = new Build(null);
50 | assertEquals(90 * MINUTES, strategy.getTimeOut(b,null),"Timeout should be the elastic default.");
51 | }
52 |
53 | @Test
54 | void failSafeTimeoutDurationWithOneBuild() throws Exception {
55 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy("200", "60", "3", true);
56 |
57 | Build b = new Build(new Build(20 * MINUTES, SUCCESS));
58 |
59 | assertEquals(60 * MINUTES, strategy.getTimeOut(b,null),"Timeout should be the elastic default.");
60 | }
61 |
62 | @Test
63 | void failSafeTimeoutDurationWithTwoBuilds() throws Exception {
64 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy("200", "60", "3", true);
65 |
66 | Build b = new Build(new Build(20 * MINUTES, SUCCESS, new Build(5 * MINUTES, SUCCESS)));
67 |
68 | assertEquals(60 * MINUTES, strategy.getTimeOut(b,null),"Timeout should be the elastic default.");
69 | }
70 |
71 | @Test
72 | void failSafeTimeoutIsNotUsed() throws Exception {
73 | BuildTimeOutStrategy strategy = new ElasticTimeOutStrategy("200", "60", "3", true);
74 |
75 | Build b = new Build(
76 | new Build(120 * MINUTES, SUCCESS,
77 | new Build(150 * MINUTES, SUCCESS)
78 | )
79 | );
80 |
81 | // Timeout should be 200 % of average of builds.
82 | assertEquals(
83 | 270 * MINUTES,
84 | strategy.getTimeOut(b,null),"Timeout should not be the elastic default.");
85 |
86 | }
87 |
88 | private class Build extends FreeStyleBuild {
89 | Build previous;
90 | long duration;
91 | Result result;
92 |
93 | Build(Build previous) throws IOException {
94 | super(Mockito.mock(FreeStyleProject.class));
95 | this.previous = previous;
96 | }
97 |
98 | Build(long duration, Result result, Build previous) throws IOException {
99 | this(previous);
100 | this.duration = duration;
101 | this.result = result;
102 | }
103 |
104 | Build(long duration, Result result) throws IOException {
105 | this(duration, result, null);
106 | }
107 |
108 | @Override
109 | public long getDuration() {
110 | return duration;
111 | }
112 |
113 | @Override
114 | public Result getResult() {
115 | return result;
116 | }
117 |
118 | @Override
119 | public FreeStyleBuild getPreviousBuild() {
120 | return previous;
121 | }
122 |
123 | @Override
124 | public void run() {
125 | }
126 |
127 | @Override
128 | public File getRootDir() {
129 | return new File(String.valueOf(directory.getRoot()), getId());
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/operations/WriteDescriptionOperationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import static org.junit.jupiter.api.Assertions.assertEquals;
28 |
29 | import java.util.Arrays;
30 |
31 | import org.junit.jupiter.api.BeforeEach;
32 | import org.junit.jupiter.api.Test;
33 |
34 | import org.jvnet.hudson.test.JenkinsRule;
35 | import org.jvnet.hudson.test.SleepBuilder;
36 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
37 |
38 | import hudson.model.FreeStyleBuild;
39 | import hudson.model.FreeStyleProject;
40 | import hudson.model.Result;
41 | import hudson.plugins.build_timeout.QuickBuildTimeOutStrategy;
42 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
43 |
44 | @WithJenkins
45 | class WriteDescriptionOperationTest {
46 |
47 | @BeforeEach
48 | void setUp() {
49 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = 0;
50 | }
51 |
52 | @Test
53 | void setDescription(JenkinsRule j) throws Exception {
54 | final String DESCRIPTION = "description to test: {0}, {0}.";
55 | final String EXPECTED = "description to test: 0, 0.";
56 |
57 | FreeStyleProject p = j.createFreeStyleProject();
58 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
59 | new QuickBuildTimeOutStrategy(5000),
60 | Arrays.asList(
61 | new WriteDescriptionOperation(DESCRIPTION),
62 | new AbortOperation()
63 | )
64 | ));
65 | p.getBuildersList().add(new SleepBuilder(10000));
66 |
67 | FreeStyleBuild b = p.scheduleBuild2(0).get();
68 | j.assertBuildStatus(Result.ABORTED, b);
69 |
70 | assertEquals(EXPECTED, b.getDescription());
71 | }
72 |
73 | @Test
74 | void setDescriptionWithoutAborting(JenkinsRule j) throws Exception {
75 | final String DESCRIPTION = "description to test: {0}, {0}.";
76 | final String EXPECTED = "description to test: 0, 0.";
77 |
78 | FreeStyleProject p = j.createFreeStyleProject();
79 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
80 | new QuickBuildTimeOutStrategy(5000),
81 | Arrays.asList(
82 | new WriteDescriptionOperation(DESCRIPTION)
83 | )
84 | ));
85 | p.getBuildersList().add(new SleepBuilder(10000));
86 |
87 | FreeStyleBuild b = p.scheduleBuild2(0).get();
88 | j.assertBuildStatusSuccess(b);
89 |
90 | assertEquals(EXPECTED, b.getDescription());
91 | }
92 |
93 | @Test
94 | void setDescriptionTwice(JenkinsRule j) throws Exception {
95 | final String DESCRIPTION1 = "description to test: {0}, {0}.";
96 | final String DESCRIPTION2 = "Another message.";
97 | final String EXPECTED = "Another message.";
98 |
99 | FreeStyleProject p = j.createFreeStyleProject();
100 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
101 | new QuickBuildTimeOutStrategy(5000),
102 | Arrays.asList(
103 | new WriteDescriptionOperation(DESCRIPTION1),
104 | new AbortOperation(),
105 | new WriteDescriptionOperation(DESCRIPTION2)
106 | )
107 | ));
108 | p.getBuildersList().add(new SleepBuilder(10000));
109 |
110 | FreeStyleBuild b = p.scheduleBuild2(0).get();
111 | j.assertBuildStatus(Result.ABORTED, b);
112 |
113 | assertEquals(EXPECTED, b.getDescription());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.impl;
26 |
27 | import hudson.model.ParametersDefinitionProperty;
28 | import hudson.model.Result;
29 | import hudson.model.Cause;
30 | import hudson.model.FreeStyleProject;
31 | import hudson.model.ParametersAction;
32 | import hudson.model.StringParameterDefinition;
33 | import hudson.model.StringParameterValue;
34 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
35 | import hudson.plugins.build_timeout.operations.AbortOperation;
36 |
37 | import java.text.SimpleDateFormat;
38 | import java.util.Arrays;
39 | import java.util.Calendar;
40 |
41 | import org.junit.jupiter.api.AfterEach;
42 | import org.junit.jupiter.api.BeforeEach;
43 | import org.junit.jupiter.api.Test;
44 |
45 | import org.jvnet.hudson.test.JenkinsRule;
46 | import org.jvnet.hudson.test.SleepBuilder;
47 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
48 |
49 | /**
50 | * Tests for {@link AbsoluteTimeOutStrategy}. Many tests for
51 | * {@link AbsoluteTimeOutStrategy} are also in
52 | * {@see BuildTimeoutWrapperIntegrationTest}
53 | */
54 | @WithJenkins
55 | class DeadlineTimeOutStrategyTest {
56 |
57 | private long origTimeout = 0;
58 |
59 | private static final int TOLERANCE_PERIOD_IN_MINUTES = 2;
60 |
61 | @BeforeEach
62 | void before() {
63 | // this allows timeout shorter than 3 minutes.
64 | origTimeout = BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS;
65 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = 1000;
66 | }
67 |
68 | @AfterEach
69 | void after() {
70 | BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS = origTimeout;
71 | }
72 |
73 | @Test
74 | void configurationWithParameter(JenkinsRule j) throws Exception {
75 | // Deadline in next three seconds. Job should be aborted in three seconds after start
76 | testWithParam(3, Result.ABORTED, j);
77 |
78 | // Deadline defined as a past time but inside tolerance period. Job should be aborted immediately
79 | testWithParam(-TOLERANCE_PERIOD_IN_MINUTES * 60 / 2, Result.ABORTED, j);
80 |
81 | // Deadline defined as a past time outside tolerance period, so effective deadline will be tomorrow. Job should be executed normally.
82 | testWithParam(-TOLERANCE_PERIOD_IN_MINUTES * 60 * 2, Result.SUCCESS, j);
83 | }
84 |
85 | @SuppressWarnings("deprecation")
86 | private void testWithParam(int timeToDeadlineInSecondsFromNow, Result expectedResult, JenkinsRule j) throws Exception {
87 | String deadline = getDeadlineTimeFromNow(timeToDeadlineInSecondsFromNow);
88 |
89 | FreeStyleProject p = j.createFreeStyleProject();
90 | // needed since Jenkins 2.3
91 | p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("DEADLINE", null)));
92 | p.getBuildWrappersList().add(
93 | new BuildTimeoutWrapper(new DeadlineTimeOutStrategy("${DEADLINE}",
94 | TOLERANCE_PERIOD_IN_MINUTES), Arrays.asList(new AbortOperation()), null));
95 | p.getBuildersList().add(new SleepBuilder(5000));
96 |
97 | j.assertBuildStatus(expectedResult, p.scheduleBuild2(0, new Cause.UserCause(),
98 | new ParametersAction(new StringParameterValue("DEADLINE", deadline))).get());
99 | }
100 |
101 | private String getDeadlineTimeFromNow(int offsetInSeconds) {
102 | Calendar deadline = Calendar.getInstance();
103 | deadline.add(Calendar.SECOND, offsetInSeconds);
104 |
105 | return new SimpleDateFormat(DeadlineTimeOutStrategy.TIME_LONG_FORMAT_PATTERN).format(deadline.getTime());
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/operations/AbortAndRestartOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015 Stefan Brausch, Jochen A. Fuerbacher
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import java.io.IOException;
28 | import java.util.logging.Level;
29 | import java.util.logging.Logger;
30 |
31 | import org.kohsuke.stapler.DataBoundConstructor;
32 |
33 | import hudson.Extension;
34 | import hudson.model.AbstractBuild;
35 | import hudson.model.AbstractProject;
36 | import hudson.model.BuildListener;
37 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
38 | import hudson.plugins.build_timeout.BuildTimeOutOperationDescriptor;
39 |
40 | import com.chikli.hudson.plugin.naginator.FixedDelay;
41 |
42 | /**
43 | * Abort the build.
44 | */
45 | public class AbortAndRestartOperation extends BuildTimeOutOperation {
46 |
47 | private final String maxRestarts;
48 |
49 | private static final Logger log = Logger.getLogger(AbortAndRestartOperation.class.getName());
50 |
51 | /**
52 | * @return max restarts.
53 | */
54 | public String getMaxRestarts() {
55 | return maxRestarts;
56 | }
57 |
58 | @DataBoundConstructor
59 | public AbortAndRestartOperation(String maxRestarts){
60 | this.maxRestarts = maxRestarts;
61 | }
62 |
63 | private static boolean isPresent() {
64 | try {
65 | Class.forName("com.chikli.hudson.plugin.naginator.NaginatorScheduleAction");
66 | return true;
67 | } catch (ClassNotFoundException ex) {
68 | log.log(Level.FINEST, "Naginator not available. ", ex);
69 | return false;
70 | }
71 | }
72 |
73 | private void rescheduleBuild(AbstractBuild, ?> build, BuildListener listener) {
74 | FixedDelay sd = new FixedDelay(0); //Reschedule now!
75 |
76 | String maxRestartsStr = null;
77 | try {
78 | maxRestartsStr = build.getEnvironment(listener).expand(this.maxRestarts);
79 | } catch (IOException | InterruptedException e) {
80 | listener.error("Failed to expand environment variables.");
81 | e.printStackTrace(listener.getLogger());
82 | return;
83 | }
84 |
85 | int maxRestarts = 0;
86 | try {
87 | maxRestarts = Integer.parseInt(maxRestartsStr);
88 | } catch (NumberFormatException e) {
89 | listener.error("Invalid Maximum restarts: {0}", maxRestartsStr);
90 | e.printStackTrace(listener.getLogger());
91 | return;
92 | }
93 | build.addAction(new com.chikli.hudson.plugin.naginator.NaginatorScheduleAction(maxRestarts, sd, false));
94 | listener.getLogger().println(Messages.AbortAndRestartOperation_ScheduledRestart(maxRestarts));
95 | }
96 |
97 | /**
98 | * @param build
99 | * @param listener
100 | * @param effectiveTimeout
101 | * @return
102 | * @see hudson.plugins.build_timeout.BuildTimeOutOperation#perform(hudson.model.AbstractBuild, hudson.model.BuildListener, long)
103 | */
104 | @Override
105 | public boolean perform(AbstractBuild, ?> build, BuildListener listener, long effectiveTimeout) {
106 | if (isPresent()) {
107 | rescheduleBuild(build, listener);
108 | } else {
109 | listener.error(Messages.AbortAndRestartOperation_InstallNaginator());
110 | }
111 |
112 | return new AbortOperation().perform(build, listener, effectiveTimeout);
113 | }
114 |
115 | @Extension(optional = true)
116 | public static class DescriptorImpl extends BuildTimeOutOperationDescriptor {
117 | @Override
118 | public String getDisplayName() {
119 | return Messages.AbortAndRestartOperation_DisplayName();
120 | }
121 |
122 | @Override
123 | public boolean isApplicable(Class extends AbstractProject,?>> jobType) {
124 | return AbortAndRestartOperation.isPresent();
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategyJenkinsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2014 IKEDA Yasuyuki
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.impl;
26 |
27 | import static org.junit.jupiter.api.Assertions.assertEquals;
28 |
29 | import java.util.Arrays;
30 |
31 | import hudson.model.FreeStyleBuild;
32 | import hudson.model.Cause;
33 | import hudson.model.FreeStyleProject;
34 | import hudson.model.ParametersAction;
35 | import hudson.model.ParametersDefinitionProperty;
36 | import hudson.model.StringParameterDefinition;
37 | import hudson.model.StringParameterValue;
38 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
39 | import hudson.plugins.build_timeout.operations.AbortOperation;
40 |
41 | import org.junit.jupiter.api.Test;
42 |
43 | import org.jvnet.hudson.test.JenkinsRule;
44 | import org.jvnet.hudson.test.JenkinsRule.WebClient;
45 | import org.jvnet.hudson.test.CaptureEnvironmentBuilder;
46 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
47 |
48 | import org.htmlunit.html.HtmlForm;
49 | import org.htmlunit.html.HtmlPage;
50 |
51 | /**
52 | * Tests for {@link ElasticTimeOutStrategy} using Jenkins
53 | */
54 | @WithJenkins
55 | class ElasticTimeOutStrategyJenkinsTest {
56 |
57 | @Test
58 | void canConfigureWithWebPage(JenkinsRule j) throws Exception {
59 | FreeStyleProject p = j.createFreeStyleProject();
60 | p.getBuildWrappersList().add(
61 | new BuildTimeoutWrapper(
62 | new ElasticTimeOutStrategy("300", "3", "10"),
63 | Arrays.asList(new AbortOperation()),
64 | null
65 | )
66 | );
67 | p.save();
68 |
69 | String projectName = p.getFullName();
70 |
71 | // test configuration before configure on configuration page.
72 | {
73 | ElasticTimeOutStrategy strategy = (ElasticTimeOutStrategy)p.getBuildWrappersList().get(BuildTimeoutWrapper.class).getStrategy();
74 | assertEquals("300", strategy.getTimeoutPercentage());
75 | assertEquals("3", strategy.getTimeoutMinutesElasticDefault());
76 | assertEquals("10", strategy.getNumberOfBuilds());
77 | }
78 |
79 | // reconfigure.
80 | // This should preserve configuration.
81 | WebClient wc = j.createWebClient();
82 | HtmlPage page = wc.getPage(p, "configure");
83 | HtmlForm form = page.getFormByName("config");
84 | j.submit(form);
85 | p = j.jenkins.getItemByFullName(projectName, FreeStyleProject.class);
86 |
87 | // test configuration before configure on configuration page.
88 | {
89 | ElasticTimeOutStrategy strategy = (ElasticTimeOutStrategy)p.getBuildWrappersList().get(BuildTimeoutWrapper.class).getStrategy();
90 | assertEquals("300", strategy.getTimeoutPercentage());
91 | assertEquals("3", strategy.getTimeoutMinutesElasticDefault());
92 | assertEquals("10", strategy.getNumberOfBuilds());
93 | }
94 | }
95 |
96 | @Test
97 | void failSafeTimeoutWithVariable(JenkinsRule j) throws Exception {
98 | FreeStyleProject p = j.createFreeStyleProject();
99 | // needed since Jenkins 2.3
100 | p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("FailSafeTimeout", null)));
101 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
102 | new ElasticTimeOutStrategy("200", "${FailSafeTimeout}", "3", true),
103 | null,
104 | "TIMEOUT"
105 | ));
106 | CaptureEnvironmentBuilder ceb = new CaptureEnvironmentBuilder();
107 | p.getBuildersList().add(ceb);
108 |
109 | FreeStyleBuild b = j.assertBuildStatusSuccess(
110 | p.scheduleBuild2(
111 | 0,
112 | new Cause.UserIdCause(),
113 | new ParametersAction(new StringParameterValue(
114 | "FailSafeTimeout",
115 | "30", // 30 minutes
116 | ""
117 | ))
118 | )
119 | );
120 |
121 | assertEquals(
122 | "1800000", // value specified with FailSafeTimeout
123 | ceb.getEnvVars().get("TIMEOUT")
124 | );
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.impl;
2 |
3 | import hudson.Extension;
4 | import hudson.model.BuildListener;
5 | import hudson.model.AbstractBuild;
6 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
7 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
8 | import hudson.util.FormValidation;
9 |
10 | import java.io.IOException;
11 | import java.text.ParseException;
12 | import java.text.SimpleDateFormat;
13 | import java.util.Calendar;
14 | import java.util.Date;
15 | import java.util.StringJoiner;
16 |
17 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
18 | import org.kohsuke.stapler.DataBoundConstructor;
19 | import org.kohsuke.stapler.QueryParameter;
20 |
21 | import edu.umd.cs.findbugs.annotations.NonNull;
22 |
23 | /**
24 | * If the build reaches {@code deadlineTime}, it will be terminated.
25 | *
26 | * @author Fernando Miguélez Palomo (fernando.miguelez@gmail.com)
27 | */
28 | public class DeadlineTimeOutStrategy extends BuildTimeOutStrategy {
29 |
30 | public static final int MINIMUM_DEADLINE_TOLERANCE_IN_MINUTES = 1;
31 |
32 | protected static final String DEADLINE_REGEXP = "[0-2]?[0-9]:[0-5][0-9](:[0-5][0-9])?";
33 |
34 | protected static final String TIME_LONG_FORMAT_PATTERN = "H:mm:ss";
35 | protected static final String TIME_SHORT_FORMAT_PATTERN = "H:mm";
36 | protected static final String TIMESTAMP_FORMAT_PATTERN = "yyyy-MM-dd H:mm:ss";
37 |
38 | private final String deadlineTime;
39 | private final int deadlineToleranceInMinutes;
40 |
41 | /**
42 | * @return deadline time
43 | */
44 | public String getDeadlineTime() {
45 | return deadlineTime;
46 | }
47 |
48 | /**
49 | * @return deadline tolerance in minutes
50 | */
51 | public int getDeadlineToleranceInMinutes() {
52 | return deadlineToleranceInMinutes;
53 | }
54 |
55 | @DataBoundConstructor
56 | public DeadlineTimeOutStrategy(String deadlineTime, int deadlineToleranceInMinutes) {
57 | this.deadlineTime = deadlineTime;
58 | this.deadlineToleranceInMinutes = deadlineToleranceInMinutes <= MINIMUM_DEADLINE_TOLERANCE_IN_MINUTES ? MINIMUM_DEADLINE_TOLERANCE_IN_MINUTES
59 | : deadlineToleranceInMinutes;
60 | }
61 |
62 | @Override
63 | public long getTimeOut(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener) throws InterruptedException,
64 | MacroEvaluationException, IOException, IllegalArgumentException {
65 |
66 | Calendar now = Calendar.getInstance();
67 | Calendar deadlineTimestamp = Calendar.getInstance();
68 |
69 | String expandedDeadlineTime = expandAll(build, listener, deadlineTime);
70 |
71 | deadlineTimestamp.setTime(parseDeadline(expandedDeadlineTime));
72 | deadlineTimestamp.set(Calendar.YEAR, now.get(Calendar.YEAR));
73 | deadlineTimestamp.set(Calendar.MONTH, now.get(Calendar.MONTH));
74 | deadlineTimestamp.set(Calendar.DAY_OF_MONTH, now.get(Calendar.DAY_OF_MONTH));
75 |
76 | Calendar deadlineTimestampWithTolerance = (Calendar) deadlineTimestamp.clone();
77 | deadlineTimestampWithTolerance.add(Calendar.MINUTE, deadlineToleranceInMinutes);
78 |
79 | if (deadlineTimestamp.compareTo(now) <= 0 && deadlineTimestampWithTolerance.compareTo(now) > 0) {
80 | // Deadline time is a past moment but inside tolerance period. Terminate build immediately.
81 | listener.getLogger().println(
82 | Messages.DeadlineTimeOutStrategy_ImmediatelyTerminate(expandedDeadlineTime,
83 | deadlineToleranceInMinutes));
84 | return 0;
85 | }
86 |
87 | while (deadlineTimestamp.before(now)) {
88 | // Deadline time is a past moment. Increment one day till deadline timestamp is in the future.
89 | deadlineTimestamp.add(Calendar.DAY_OF_MONTH, 1);
90 | }
91 |
92 | listener.getLogger().println(
93 | Messages.DeadlineTimeOutStrategy_NextDeadline(new SimpleDateFormat(TIMESTAMP_FORMAT_PATTERN).format(deadlineTimestamp
94 | .getTime())));
95 |
96 | return deadlineTimestamp.getTimeInMillis() - now.getTimeInMillis();
97 | }
98 |
99 | private static Date parseDeadline(@NonNull String deadline) throws IllegalArgumentException {
100 |
101 | if (deadline.matches(DEADLINE_REGEXP)) {
102 | try {
103 | if (deadline.length() > 5) {
104 | return new SimpleDateFormat(TIME_LONG_FORMAT_PATTERN).parse(deadline);
105 | } else {
106 | return new SimpleDateFormat(TIME_SHORT_FORMAT_PATTERN).parse(deadline);
107 | }
108 | } catch (ParseException e) {
109 | }
110 | }
111 |
112 | throw new IllegalArgumentException(Messages.DeadlineTimeOutStrategy_InvalidDeadlineFormat(deadline));
113 | }
114 |
115 | @Override
116 | public String toString() {
117 | return new StringJoiner(", ", DeadlineTimeOutStrategy.class.getSimpleName() + "[", "]")
118 | .add("deadlineTime='" + deadlineTime + "'")
119 | .add("deadlineToleranceInMinutes=" + deadlineToleranceInMinutes)
120 | .toString();
121 | }
122 |
123 | @Extension
124 | public static class DescriptorImpl extends BuildTimeOutStrategyDescriptor {
125 | @Override
126 | public String getDisplayName() {
127 | return Messages.DeadlineTimeOutStrategy_DisplayName();
128 | }
129 |
130 | public FormValidation doCheckDeadlineTime(@QueryParameter String value) {
131 | if (hasMacros(value)) {
132 | return FormValidation.warning(Messages.DeadlineTimeOutStrategy_DeadlineFormatWithMacros());
133 | } else {
134 | try {
135 | parseDeadline(value);
136 | return FormValidation.ok();
137 | } catch (IllegalArgumentException e) {
138 | return FormValidation.error(e.getMessage());
139 | }
140 | }
141 | }
142 |
143 | @Override
144 | public boolean isApplicableAsBuildStep() {
145 | return true;
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.impl;
2 |
3 | import hudson.Extension;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.BuildListener;
6 | import hudson.model.Descriptor;
7 | import hudson.model.Result;
8 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
9 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
10 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
11 | import hudson.util.ListBoxModel;
12 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
13 | import org.kohsuke.stapler.DataBoundConstructor;
14 |
15 | import edu.umd.cs.findbugs.annotations.NonNull;
16 | import java.io.IOException;
17 | import java.util.StringJoiner;
18 |
19 | public class ElasticTimeOutStrategy extends BuildTimeOutStrategy {
20 |
21 | private final String timeoutPercentage;
22 |
23 | private final String numberOfBuilds;
24 |
25 | private final boolean failSafeTimeoutDuration;
26 |
27 | /**
28 | * The timeout to use if there are no valid builds in the build
29 | * history (ie, no successful or unstable builds)
30 | */
31 | private final String timeoutMinutesElasticDefault;
32 |
33 | /**
34 | * @return how long percentage of the average duration to timeout.
35 | */
36 | public String getTimeoutPercentage() {
37 | return timeoutPercentage;
38 | }
39 |
40 | /**
41 | * @return the number of last builds to use to calculate average duration.
42 | */
43 | public String getNumberOfBuilds() {
44 | return numberOfBuilds;
45 | }
46 |
47 | /**
48 | * @return the default minutes to timeout used when failed to calculate average duration
49 | */
50 | public String getTimeoutMinutesElasticDefault() {
51 | return timeoutMinutesElasticDefault;
52 | }
53 |
54 | /**
55 | * @return if fail-safe timeout needs to be used
56 | */
57 | public boolean isFailSafeTimeoutDuration() {
58 | return failSafeTimeoutDuration;
59 | }
60 |
61 | @Deprecated
62 | public ElasticTimeOutStrategy(int timeoutPercentage, int timeoutMinutesElasticDefault, int numberOfBuilds) {
63 | this(Integer.toString(timeoutPercentage), Integer.toString(timeoutMinutesElasticDefault), Integer.toString(numberOfBuilds), false);
64 | }
65 |
66 | @Deprecated
67 | public ElasticTimeOutStrategy(String timeoutPercentage, String timeoutMinutesElasticDefault, String numberOfBuilds) {
68 | this(timeoutPercentage, timeoutMinutesElasticDefault, numberOfBuilds, false);
69 | }
70 |
71 | @DataBoundConstructor
72 | public ElasticTimeOutStrategy(String timeoutPercentage, String timeoutMinutesElasticDefault, String numberOfBuilds, boolean failSafeTimeoutDuration) {
73 | this.timeoutPercentage = timeoutPercentage;
74 | this.timeoutMinutesElasticDefault = timeoutMinutesElasticDefault;
75 | this.numberOfBuilds = numberOfBuilds;
76 | this.failSafeTimeoutDuration = failSafeTimeoutDuration;
77 | }
78 |
79 | @Override
80 | public long getTimeOut(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener)
81 | throws InterruptedException, MacroEvaluationException, IOException {
82 | double elasticTimeout = getElasticTimeout(Integer.parseInt(expandAll(build,listener,getTimeoutPercentage())), build, listener);
83 | if (elasticTimeout == 0) {
84 | return Math.max(BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS, Integer.parseInt(expandAll(build, listener, getTimeoutMinutesElasticDefault())) * MINUTES);
85 | } else {
86 | if (isFailSafeTimeoutDuration()) {
87 | return Math.max(Integer.parseInt(expandAll(build, listener, getTimeoutMinutesElasticDefault())) * MINUTES, (long) elasticTimeout);
88 | } else {
89 | return (long) Math.max(BuildTimeoutWrapper.MINIMUM_TIMEOUT_MILLISECONDS, elasticTimeout);
90 | }
91 | }
92 | }
93 |
94 | private double getElasticTimeout(int timeoutPercentage, @NonNull AbstractBuild, ?> build, @NonNull BuildListener listener)
95 | throws InterruptedException, MacroEvaluationException, IOException {
96 | return timeoutPercentage * .01D * (timeoutPercentage > 0 ? averageDuration(build,listener) : 0);
97 | }
98 |
99 | private double averageDuration(@NonNull AbstractBuild, ?> build, @NonNull BuildListener listener)
100 | throws InterruptedException, MacroEvaluationException, IOException {
101 | int nonFailingBuilds = 0;
102 | int durationSum = 0;
103 | int numberOfBuilds = Integer.parseInt(expandAll(build, listener, getNumberOfBuilds()));
104 |
105 | while(build != null && build.getPreviousBuild() != null && nonFailingBuilds < numberOfBuilds) {
106 | build = build.getPreviousBuild();
107 | if (build != null && build.getResult() != null &&
108 | build.getResult().isBetterOrEqualTo(Result.UNSTABLE)) {
109 | durationSum += build.getDuration();
110 | nonFailingBuilds++;
111 | }
112 | }
113 |
114 | return nonFailingBuilds > 0 ? ((double)durationSum) / nonFailingBuilds : 0;
115 | }
116 |
117 | @Override
118 | public String toString() {
119 | return new StringJoiner(", ", ElasticTimeOutStrategy.class.getSimpleName() + "[", "]")
120 | .add("timeoutPercentage='" + timeoutPercentage + "'")
121 | .add("numberOfBuilds='" + numberOfBuilds + "'")
122 | .add("failSafeTimeoutDuration=" + failSafeTimeoutDuration)
123 | .add("timeoutMinutesElasticDefault='" + timeoutMinutesElasticDefault + "'")
124 | .toString();
125 | }
126 |
127 | public Descriptor getDescriptor() {
128 | return DESCRIPTOR;
129 | }
130 |
131 | @Extension
132 | public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
133 |
134 | public static class DescriptorImpl extends BuildTimeOutStrategyDescriptor {
135 |
136 | @Override
137 | public String getDisplayName() {
138 | return Messages.ElasticTimeOutStrategy_DisplayName();
139 | }
140 |
141 | public int[] getPercentages() {
142 | return new int[] {150,200,250,300,350,400};
143 | }
144 |
145 | public ListBoxModel doFillTimeoutPercentageItems() {
146 | ListBoxModel m = new ListBoxModel();
147 | for (int option : getPercentages()) {
148 | String s = String.valueOf(option);
149 | m.add(s + "%", s);
150 | }
151 | return m;
152 | }
153 |
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/BuildStepWithTimeout.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout;
2 |
3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
4 | import hudson.Extension;
5 | import hudson.Launcher;
6 | import hudson.model.AbstractBuild;
7 | import hudson.model.AbstractProject;
8 | import hudson.model.Build;
9 | import hudson.model.BuildListener;
10 | import hudson.model.Descriptor;
11 | import hudson.model.Run;
12 | import hudson.model.TaskListener;
13 | import hudson.plugins.build_timeout.operations.AbortOperation;
14 | import hudson.tasks.BuildStep;
15 | import hudson.tasks.BuildStepDescriptor;
16 | import hudson.tasks.BuildStepMonitor;
17 | import hudson.tasks.Builder;
18 | import hudson.triggers.SafeTimerTask;
19 | import hudson.triggers.Trigger;
20 | import jenkins.model.Jenkins;
21 | import net.sf.json.JSONObject;
22 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
23 | import org.kohsuke.stapler.DataBoundConstructor;
24 | import org.kohsuke.stapler.StaplerRequest2;
25 |
26 | import java.io.IOException;
27 | import java.util.ArrayList;
28 | import java.util.Collections;
29 | import java.util.List;
30 | import java.util.Timer;
31 | import java.util.TimerTask;
32 |
33 |
34 | public class BuildStepWithTimeout extends Builder implements BuildStep {
35 | private final BuildTimeOutStrategy strategy;
36 | private final BuildStep buildStep;
37 | private final List operationList;
38 |
39 | @DataBoundConstructor
40 | public BuildStepWithTimeout(BuildStep buildStep, BuildTimeOutStrategy strategy, List operationList) {
41 | this.strategy = strategy;
42 | this.buildStep = buildStep;
43 | if (operationList != null && !operationList.isEmpty()) {
44 | this.operationList = operationList;
45 | }
46 | else {
47 | this.operationList = Collections.emptyList();
48 | }
49 |
50 | }
51 |
52 | public List getOperationList() {
53 | return operationList;
54 | }
55 |
56 |
57 | public BuildStep getBuildStep() {
58 | return buildStep;
59 | }
60 |
61 | private long getTimeout(Run run, TaskListener listener) throws IOException, InterruptedException {
62 | try {
63 | return strategy.getTimeOut((AbstractBuild, ?>) run, (BuildListener) listener);
64 | } catch (MacroEvaluationException e) {
65 | e.printStackTrace(listener.getLogger());
66 | listener.error("Can't evaluate timeout - timeout would be disabled");
67 | return Long.MAX_VALUE;
68 | }
69 | }
70 |
71 | @Override
72 | public boolean perform(AbstractBuild,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
73 | return perform((Build)build, launcher, listener);
74 | }
75 |
76 | @Override
77 | @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "No adequate replacement for Trigger.timer found")
78 | public boolean perform(final Build,?> build, final Launcher launcher, final BuildListener listener) throws InterruptedException, IOException {
79 | final Timer timer = Trigger.timer; // FIXME TODO replace with Timer
80 | final long delay = getTimeout(build, listener);
81 |
82 | final TimerTask task = new SafeTimerTask() {
83 | @Override
84 | public void doRun() {
85 | if (operationList.isEmpty()) {
86 | new AbortOperation().perform(build, listener, delay);
87 | }
88 |
89 | for (BuildTimeOutOperation op : operationList) {
90 | op.perform(build, listener, delay);
91 | }
92 | }
93 | };
94 |
95 | try {
96 | timer.schedule(task, delay);
97 | return buildStep.perform(build, launcher, listener);
98 | } finally {
99 | task.cancel();
100 | }
101 | }
102 |
103 | public BuildTimeOutStrategy getStrategy() {
104 | return strategy;
105 | }
106 |
107 | @Override
108 | public BuildStepMonitor getRequiredMonitorService() {
109 | return buildStep.getRequiredMonitorService();
110 | }
111 |
112 | @Extension
113 | public static class DescriptorImpl extends BuildStepDescriptor {
114 | @Override
115 | public BuildStepWithTimeout newInstance(StaplerRequest2 req, JSONObject formData)
116 | throws hudson.model.Descriptor.FormException {
117 | BuildStep buildstep = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "buildStep", BuildStep.class);
118 | BuildTimeOutStrategy strategy = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "strategy", BuildTimeOutStrategy.class);
119 | List operationList = newInstancesFromHeteroList(req, formData, "operationList", getOperations());
120 | return new BuildStepWithTimeout(buildstep, strategy, operationList);
121 | }
122 |
123 | @Override
124 | public String getDisplayName() {
125 | return Messages.BuildStepWithTimeout_DisplayName();
126 | }
127 |
128 | @Override
129 | public boolean isApplicable(Class extends AbstractProject> jobType) {
130 | return true;
131 | }
132 |
133 | public List> getBuildStepWithTimeoutRunners() {
134 | List> buildsteps = new ArrayList>(Builder.all());
135 | buildsteps.remove(this);
136 | return buildsteps;
137 | }
138 |
139 | public List getStrategies() {
140 | List descriptors = Jenkins.getActiveInstance().getDescriptorList(BuildTimeOutStrategy.class);
141 | List supportedStrategies = new ArrayList<>(descriptors.size());
142 |
143 | for(BuildTimeOutStrategyDescriptor descriptor : descriptors) {
144 | if (descriptor.isApplicableAsBuildStep()) {
145 | supportedStrategies.add(descriptor);
146 | }
147 | }
148 |
149 | return supportedStrategies;
150 | }
151 |
152 | @SuppressWarnings("unchecked")
153 | public List getOperations(AbstractProject,?> project) {
154 | return BuildTimeOutOperationDescriptor.all((Class extends AbstractProject, ?>>)project.getClass());
155 | }
156 |
157 | public List getOperations() {
158 | return BuildTimeOutOperationDescriptor.all();
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/build_timeout/operations/AbortAndRestartOperationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015 Jochen A. Fuerbacher
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package hudson.plugins.build_timeout.operations;
26 |
27 | import static org.junit.jupiter.api.Assertions.*;
28 |
29 | import java.util.Arrays;
30 | import java.util.LinkedList;
31 |
32 | import hudson.model.ParametersDefinitionProperty;
33 | import hudson.model.StringParameterDefinition;
34 | import org.junit.jupiter.api.Test;
35 |
36 | import org.jvnet.hudson.test.JenkinsRule;
37 | import org.jvnet.hudson.test.SleepBuilder;
38 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
39 |
40 | import hudson.model.Cause;
41 | import hudson.model.FreeStyleProject;
42 | import hudson.model.ParametersAction;
43 | import hudson.model.StringParameterValue;
44 | import hudson.model.Result;
45 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
46 | import hudson.plugins.build_timeout.QuickBuildTimeOutStrategy;
47 | import hudson.plugins.build_timeout.BuildTimeoutWrapper;
48 |
49 | @WithJenkins
50 | class AbortAndRestartOperationTest {
51 |
52 | @Test
53 | void abortAndRestartOnce(JenkinsRule j) throws Exception {
54 | FreeStyleProject testproject = j.createFreeStyleProject();
55 |
56 | QuickBuildTimeOutStrategy strategy = new QuickBuildTimeOutStrategy(5000);
57 | AbortAndRestartOperation operation = new AbortAndRestartOperation("1"); //Number of restarts
58 | LinkedList list = new LinkedList<>();
59 | list.add(operation);
60 |
61 | BuildTimeoutWrapper wrapper = new BuildTimeoutWrapper(strategy,list,"");
62 | testproject.getBuildWrappersList().add(wrapper);
63 |
64 |
65 | testproject.getBuildersList().add(new SleepBuilder(5*60*1000)); //5 minutes
66 |
67 | testproject.scheduleBuild(new Cause.UserIdCause());
68 |
69 | j.waitUntilNoActivityUpTo(25000);
70 |
71 | assertNotNull(testproject.getFirstBuild());
72 | assertNotEquals(testproject.getFirstBuild(), testproject.getLastBuild());
73 | assertEquals(2, testproject.getBuilds().size());
74 |
75 | assertEquals(Result.ABORTED, testproject.getFirstBuild().getResult());
76 | assertEquals(Result.ABORTED, testproject.getLastBuild().getResult());
77 | }
78 |
79 | @Test
80 | void abortAndRestartTwice(JenkinsRule j) throws Exception {
81 | FreeStyleProject testproject = j.createFreeStyleProject();
82 |
83 | QuickBuildTimeOutStrategy strategy = new QuickBuildTimeOutStrategy(5000);
84 | AbortAndRestartOperation operation = new AbortAndRestartOperation("2"); //Number of restarts
85 | LinkedList list = new LinkedList<>();
86 | list.add(operation);
87 |
88 | BuildTimeoutWrapper wrapper = new BuildTimeoutWrapper(strategy,list,"");
89 | testproject.getBuildWrappersList().add(wrapper);
90 |
91 | testproject.getBuildersList().add(new SleepBuilder(5*60*1000)); //5 minutes
92 |
93 | assertTrue(testproject.getBuilds().isEmpty());
94 |
95 | testproject.scheduleBuild(new Cause.UserIdCause());
96 |
97 | j.waitUntilNoActivityUpTo(50000);
98 |
99 | assertNotNull(testproject.getFirstBuild());
100 | assertNotEquals(testproject.getFirstBuild(), testproject.getLastBuild());
101 | assertEquals(3, testproject.getBuilds().size());
102 |
103 | assertEquals(Result.ABORTED, testproject.getBuildByNumber(1).getResult());
104 | assertEquals(Result.ABORTED, testproject.getBuildByNumber(2).getResult());
105 | assertEquals(Result.ABORTED, testproject.getBuildByNumber(3).getResult());
106 | }
107 |
108 | @Test
109 | void usingVariable(JenkinsRule j) throws Exception {
110 | FreeStyleProject p = j.createFreeStyleProject();
111 | // needed since Jenkins 2.3
112 | p.addProperty(new ParametersDefinitionProperty(new StringParameterDefinition("RESTART", null)));
113 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
114 | new QuickBuildTimeOutStrategy(1000),
115 | Arrays.asList(new AbortAndRestartOperation("${RESTART}")),
116 | ""
117 | ));
118 |
119 | p.getBuildersList().add(new SleepBuilder(5*60*1000)); //5 minutes
120 |
121 | j.assertBuildStatus(
122 | Result.ABORTED,
123 | p.scheduleBuild2(
124 | 0,
125 | new Cause.UserIdCause(),
126 | new ParametersAction(new StringParameterValue("RESTART", "1"))
127 | ).get()
128 | );
129 | j.waitUntilNoActivityUpTo(25000);
130 |
131 | assertEquals(2, p.getBuilds().size());
132 | }
133 |
134 | @Test
135 | void usingBadRestart(JenkinsRule j) throws Exception {
136 | FreeStyleProject p = j.createFreeStyleProject();
137 | p.getBuildWrappersList().add(new BuildTimeoutWrapper(
138 | new QuickBuildTimeOutStrategy(1000),
139 | Arrays.asList(new AbortAndRestartOperation("${RESTART}")),
140 | ""
141 | ));
142 |
143 | p.getBuildersList().add(new SleepBuilder(5*60*1000)); //5 minutes
144 |
145 | j.assertBuildStatus(
146 | Result.ABORTED,
147 | p.scheduleBuild2(
148 | 0,
149 | new Cause.UserIdCause(),
150 | new ParametersAction(new StringParameterValue("RESTART", "xxx"))
151 | ).get()
152 | );
153 | j.waitUntilNoActivityUpTo(25000);
154 |
155 | // Build is not restarted
156 | assertEquals(1, p.getBuilds().size());
157 | }
158 | }
159 |
160 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/build_timeout/global/GlobalTimeOutConfiguration.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.build_timeout.global;
2 |
3 | import hudson.Extension;
4 | import hudson.model.AbstractBuild;
5 | import hudson.model.AbstractProject;
6 | import hudson.model.BuildListener;
7 | import hudson.model.Project;
8 | import hudson.plugins.build_timeout.BuildTimeOutOperation;
9 | import hudson.plugins.build_timeout.BuildTimeOutOperationDescriptor;
10 | import hudson.plugins.build_timeout.BuildTimeOutStrategy;
11 | import hudson.plugins.build_timeout.BuildTimeOutStrategyDescriptor;
12 | import hudson.plugins.build_timeout.BuildStepWithTimeout;
13 | import hudson.plugins.build_timeout.operations.AbortOperation;
14 | import hudson.tasks.Builder;
15 | import jenkins.model.GlobalConfiguration;
16 | import jenkins.model.Jenkins;
17 | import net.sf.json.JSONObject;
18 | import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
19 | import org.kohsuke.stapler.StaplerRequest2;
20 |
21 | import jakarta.inject.Inject;
22 | import java.io.IOException;
23 | import java.time.Duration;
24 | import java.util.Collections;
25 | import java.util.LinkedList;
26 | import java.util.List;
27 | import java.util.Optional;
28 | import java.util.logging.Logger;
29 | import java.util.stream.Collectors;
30 |
31 | import static java.util.logging.Level.WARNING;
32 |
33 | @Extension
34 | public class GlobalTimeOutConfiguration extends GlobalConfiguration implements TimeOutProvider {
35 | private static final Logger log = Logger.getLogger(GlobalTimeOutConfiguration.class.getName());
36 | private transient Jenkins jenkins;
37 | private BuildTimeOutStrategy strategy;
38 | private List operations;
39 | private boolean overwriteable;
40 |
41 | public GlobalTimeOutConfiguration() {
42 | load();
43 | }
44 |
45 | @Inject
46 | public void setJenkins(Jenkins jenkins) {
47 | this.jenkins = jenkins;
48 | }
49 |
50 | /**
51 | * Unchecking the 'Enable Global Timeout' box sends a null object for
52 | * timeout.global in the json representation of the form submission.
53 | *
54 | * Binding this to the current class leaves the previous values.
55 | * To get around this binding problem, we explicitly null out these fields
56 | * before saving.
57 | *
58 | * @param req the request object
59 | * @param json form data as json
60 | * @return always true
61 | */
62 | @Override
63 | public boolean configure(StaplerRequest2 req, JSONObject json) {
64 | JSONObject settings = json.getJSONObject("timeout").getJSONObject("global");
65 | overwriteable = false;
66 | if (settings.isNullObject()) {
67 | strategy = null;
68 | operations = null;
69 | log.info("global timeout has been cleared");
70 | } else {
71 | req.bindJSON(this, settings);
72 | log.info(() -> String.format("global timeout updated to %s with operations: %s", strategy, describeOperations()));
73 | }
74 | save();
75 | return true;
76 | }
77 |
78 | @Override
79 | public synchronized void load() {
80 | super.load();
81 | log.info(() -> {
82 | if (strategy == null) {
83 | return "global timeout not set";
84 | }
85 | return String.format("global timeout loaded as %s with operations: %s", strategy, describeOperations());
86 | });
87 | }
88 |
89 | @Override
90 | public Optional timeOutFor(AbstractBuild,?> build, BuildListener listener) {
91 | try {
92 | List builders = ((Project, ?>) build.getProject()).getBuilders();
93 | Optional timeoutBuildStep = builders.stream().filter(builder -> builder instanceof BuildStepWithTimeout).findAny();
94 |
95 | if (strategy == null || (timeoutBuildStep.isPresent() && getOverwriteable())) {
96 | return Optional.empty();
97 | }
98 | return Optional.of(Duration.ofMillis(strategy.getTimeOut(build, listener)));
99 | } catch (ClassCastException e) {
100 | // log.log(WARNING, e, () -> String.format("%s cannot allow individual jobs to overwrite timeout due to ClassCastException", build.getExternalizableId()));
101 | if (strategy == null) {
102 | return Optional.empty();
103 | }
104 | try {
105 | return Optional.of(Duration.ofMillis(strategy.getTimeOut(build, listener)));
106 | } catch (InterruptedException | MacroEvaluationException | IOException ex) {
107 | log.log(WARNING, ex, () -> String.format("%s failed to determine time out", build.getExternalizableId()));
108 | return Optional.empty();
109 | }
110 | } catch (InterruptedException | MacroEvaluationException | IOException e) {
111 | log.log(WARNING, e, () -> String.format("%s failed to determine time out", build.getExternalizableId()));
112 | return Optional.empty();
113 | }
114 | }
115 |
116 | public boolean isEnabled() {
117 | return strategy != null;
118 | }
119 |
120 | public boolean getOverwriteable() {
121 | return overwriteable;
122 | }
123 |
124 | public void setOverwriteable(boolean overwriteable) {
125 | this.overwriteable = overwriteable;
126 | }
127 |
128 | @Override
129 | public List getOperations() {
130 | List nullSafe = operations == null ? new LinkedList<>() : operations;
131 | if (nullSafe.isEmpty()) {
132 | nullSafe.add(new AbortOperation());
133 | }
134 | return nullSafe;
135 | }
136 |
137 | public void setOperations(List operations) {
138 | this.operations = operations;
139 | }
140 |
141 | public BuildTimeOutStrategy getStrategy() {
142 | return strategy;
143 | }
144 |
145 | public void setStrategy(BuildTimeOutStrategy strategy) {
146 | this.strategy = strategy;
147 | }
148 |
149 | public List getAllStrategies() {
150 | return jenkins.getDescriptorList(BuildTimeOutStrategy.class);
151 | }
152 |
153 | public List getAllOperations() {
154 | return jenkins.getDescriptorList(BuildTimeOutOperation.class);
155 | }
156 |
157 | private String describeOperations() {
158 | List nullSafe = operations == null ? Collections.emptyList() : operations;
159 | if (nullSafe.isEmpty()) {
160 | return "(none)";
161 | }
162 | return nullSafe.stream()
163 | .map(BuildTimeOutOperation::getClass)
164 | .map(Class::getSimpleName)
165 | .sorted()
166 | .collect(Collectors.joining(", "));
167 | }
168 | }
169 |
--------------------------------------------------------------------------------