├── .github ├── CODEOWNERS ├── release-drafter.yml ├── dependabot.yml └── workflows │ ├── release-drafter.yml │ └── jenkins-security-scan.yml ├── .mvn ├── maven.config └── extensions.xml ├── doc ├── build-step.png ├── global-config.png └── build-environment.png ├── src ├── main │ ├── resources │ │ ├── hudson │ │ │ └── plugins │ │ │ │ └── build_timeout │ │ │ │ ├── operations │ │ │ │ ├── FailOperation │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ └── help_es.html │ │ │ │ ├── AbortAndRestartOperation │ │ │ │ │ ├── help-maxRestarts_ja.html │ │ │ │ │ ├── help-maxRestarts.html │ │ │ │ │ ├── config_ja.properties │ │ │ │ │ └── config.jelly │ │ │ │ ├── AbortOperation │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ └── help_es.html │ │ │ │ ├── WriteDescriptionOperation │ │ │ │ │ ├── help-description_ja.html │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help-description.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── help-description_es.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── config_ja.properties │ │ │ │ │ └── config.jelly │ │ │ │ ├── BuildStepOperation │ │ │ │ │ ├── help-continueEvenFailed_ja.html │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help-enabled_ja.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── global_es.properties │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help-continueEvenFailed.html │ │ │ │ │ ├── help-enabled.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── help-continueEvenFailed_es.html │ │ │ │ │ ├── help-enabled_es.html │ │ │ │ │ ├── help-createLauncher_ja.html │ │ │ │ │ ├── help-createLauncher.html │ │ │ │ │ ├── help-createLauncher_es.html │ │ │ │ │ ├── global_ja.properties │ │ │ │ │ ├── config_ja.properties │ │ │ │ │ ├── global.jelly │ │ │ │ │ └── config.jelly │ │ │ │ ├── Messages_es.properties │ │ │ │ ├── Messages.properties │ │ │ │ └── Messages_ja.properties │ │ │ │ ├── BuildTimeoutWrapper │ │ │ │ ├── help-strategyRaw_ja.html │ │ │ │ ├── help-strategyRaw.html │ │ │ │ ├── help-strategyRaw_es.html │ │ │ │ ├── help-operationList_ja.html │ │ │ │ ├── help-operationList.html │ │ │ │ ├── config_es.properties │ │ │ │ ├── help-operationList_es.html │ │ │ │ ├── config.jelly │ │ │ │ ├── config_ja.properties │ │ │ │ └── help-strategy.groovy │ │ │ │ ├── impl │ │ │ │ ├── AbsoluteTimeOutStrategy │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── help-timeoutMinutes_ja.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── help-timeoutMinutes_es.html │ │ │ │ │ ├── help-timeoutMinutes.html │ │ │ │ │ ├── config.jelly │ │ │ │ │ └── config_ja.properties │ │ │ │ ├── NoActivityTimeOutStrategy │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── help-timeoutSecondsString_ja.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── help-timeoutSecondsString.html │ │ │ │ │ ├── help-timeoutSecondsString_es.html │ │ │ │ │ ├── config_ja.properties │ │ │ │ │ └── config.jelly │ │ │ │ ├── LikelyStuckTimeOutStrategy │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ └── config.jelly │ │ │ │ ├── ElasticTimeOutStrategy │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── help-timeoutPercentage_ja.html │ │ │ │ │ ├── help-timeoutPercentage.html │ │ │ │ │ ├── help-timeoutPercentage_es.html │ │ │ │ │ ├── config.jelly │ │ │ │ │ └── config_ja.properties │ │ │ │ ├── DeadlineTimeOutStrategy │ │ │ │ │ ├── help_ja.html │ │ │ │ │ ├── help.html │ │ │ │ │ ├── help_es.html │ │ │ │ │ ├── config_es.properties │ │ │ │ │ ├── help-deadlineTime_ja.html │ │ │ │ │ ├── help-deadlineToleranceInMinutes_ja.html │ │ │ │ │ ├── help-deadlineTime.html │ │ │ │ │ ├── help-deadlineTime_es.html │ │ │ │ │ ├── help-deadlineToleranceInMinutes.html │ │ │ │ │ ├── config.jelly │ │ │ │ │ ├── help-deadlineToleranceInMinutes_es.html │ │ │ │ │ └── config_ja.properties │ │ │ │ ├── Messages_es.properties │ │ │ │ ├── Messages.properties │ │ │ │ └── Messages_ja.properties │ │ │ │ ├── Messages_es.properties │ │ │ │ ├── Messages.properties │ │ │ │ ├── BuildStepWithTimeout │ │ │ │ ├── config.jelly │ │ │ │ └── config_ja.properties │ │ │ │ ├── global │ │ │ │ └── GlobalTimeOutConfiguration │ │ │ │ │ └── config.jelly │ │ │ │ ├── Messages_ja.properties │ │ │ │ └── nestedHelp.js │ │ └── index.jelly │ └── java │ │ └── hudson │ │ └── plugins │ │ └── build_timeout │ │ ├── global │ │ ├── TimeOutStore.java │ │ ├── TimeOut.java │ │ ├── TimeOutProvider.java │ │ ├── Lifecycle.java │ │ ├── GlobalTimeOutModule.java │ │ ├── InMemoryTimeOutStore.java │ │ ├── GlobalTimeOutRunListener.java │ │ ├── TimeOutTask.java │ │ └── GlobalTimeOutConfiguration.java │ │ ├── BuildTimeOutStrategyDescriptor.java │ │ ├── impl │ │ ├── LikelyStuckTimeOutStrategy.java │ │ ├── AbsoluteTimeOutStrategy.java │ │ ├── NoActivityTimeOutStrategy.java │ │ ├── DeadlineTimeOutStrategy.java │ │ └── ElasticTimeOutStrategy.java │ │ ├── BuildTimeOutOperation.java │ │ ├── BuildTimeOutOperationDescriptor.java │ │ ├── operations │ │ ├── FailOperation.java │ │ ├── AbortOperation.java │ │ ├── WriteDescriptionOperation.java │ │ └── AbortAndRestartOperation.java │ │ ├── BuildTimeOutUtility.java │ │ ├── BuildTimeOutStrategy.java │ │ └── BuildStepWithTimeout.java └── test │ ├── resources │ └── hudson │ │ └── plugins │ │ └── build_timeout │ │ ├── BuildTimeoutWrapperIntegrationTest │ │ ├── migrationFrom_1_13 │ │ │ ├── config.xml │ │ │ └── jobs │ │ │ │ └── NoActivityTimeOutStrategy │ │ │ │ └── config.xml │ │ └── migrationFrom_1_12_2 │ │ │ ├── config.xml │ │ │ └── jobs │ │ │ ├── AbortWithDescription │ │ │ └── config.xml │ │ │ ├── FailWithDescription │ │ │ └── config.xml │ │ │ ├── FailWithoutDescription │ │ │ └── config.xml │ │ │ └── AbortWithoutDescription │ │ │ └── config.xml │ │ └── operations │ │ └── BuildStepOperationTest │ │ └── NoDataBoundConstructorBuilder │ │ └── config.jelly │ └── java │ └── hudson │ └── plugins │ └── build_timeout │ ├── FakeBuildStep.java │ ├── QuickBuildTimeOutStrategy.java │ ├── global │ ├── InMemoryTimeOutStoreTest.java │ ├── GlobalTimeOutRunListenerTest.java │ └── TimeOutTaskTest.java │ ├── BuildStepWithTimeoutTest.java │ ├── impl │ ├── AbsoluteTimeOutStrategyTest.java │ ├── ElasticTimeOutStrategyTest.java │ ├── DeadlineTimeOutStrategyTest.java │ └── ElasticTimeOutStrategyJenkinsTest.java │ └── operations │ ├── WriteDescriptionOperationTest.java │ └── AbortAndRestartOperationTest.java ├── .gitignore ├── Jenkinsfile ├── README.adoc └── pom.xml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/build-timeout-plugin-developers 2 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | tag-template: build-timeout-$NEXT_MINOR_VERSION 3 | -------------------------------------------------------------------------------- /doc/build-step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/doc/build-step.png -------------------------------------------------------------------------------- /doc/global-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/doc/global-config.png -------------------------------------------------------------------------------- /doc/build-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/doc/build-environment.png -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/FailOperation/help_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルドを失敗扱いにします。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-strategyRaw_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 以下の判定方法が利用可能です。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help_ja.html: -------------------------------------------------------------------------------- 1 |

2 | 一定時間経過したらビルドを中断します。 3 |
4 |

5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 最後のログ出力から指定時間が経過したらタイムアウトします。 3 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/FailOperation/help.html: -------------------------------------------------------------------------------- 1 |
2 | The build will be marked as failed. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-strategyRaw.html: -------------------------------------------------------------------------------- 1 |
2 | Select one of following strategies: 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/FailOperation/help_es.html: -------------------------------------------------------------------------------- 1 |
2 | La ejecución se marcará como fallida. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/LikelyStuckTimeOutStrategy/help_ja.html: -------------------------------------------------------------------------------- 1 |

2 | 過去の実行に比べて極端に長い時間ビルドが実行されている場合にタイムアウトと判定します。 3 |

4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/AbortAndRestartOperation/help-maxRestarts_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 最大再起動回数。0は制限なしを表します。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-strategyRaw_es.html: -------------------------------------------------------------------------------- 1 |
2 | Elija una de las siguientes estrategias: 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help.html: -------------------------------------------------------------------------------- 1 |

2 | Terminate a build based on a fixed time-out period. 3 |

4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help_ja.html: -------------------------------------------------------------------------------- 1 |

2 | 過去 n 回の失敗していないビルドの経過時間からの比率でタイムアウトを指定します。 3 |
4 |

5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/AbortOperation/help_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルドを中止します。 3 | アクションを何も指定しなかった場合にデフォルトで実行されるアクションです。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help_es.html: -------------------------------------------------------------------------------- 1 |

2 | Abortar la ejecución basado en un tiempo máximo fijo. 3 |
4 |

-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help_ja.html: -------------------------------------------------------------------------------- 1 |

2 | HH:MM もしくは HH:MM:SS 形式で指定された時刻 (デッドライン) を超えた場合にタイムアウトします。 3 |
4 |

5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-operationList_ja.html: -------------------------------------------------------------------------------- 1 |
2 | タイムアウトが起きたときに実行する処理を指定します。 3 | 何も指定しない場合、「ビルドを中止する」が実行されます。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help-description_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルドに設定する説明。 3 | "{0}" はタイムアウト時間(分)で置き換えられます。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plugin allows you to automatically terminate a build if it's taking too long. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/LikelyStuckTimeOutStrategy/help.html: -------------------------------------------------------------------------------- 1 |

2 | Terminate a build when it has taken many times longer than previous ones. 3 |

4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/AbortAndRestartOperation/help-maxRestarts.html: -------------------------------------------------------------------------------- 1 |
2 | Count of maximum restarts. 0 means without a limit. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルドの説明に追記します。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help.html: -------------------------------------------------------------------------------- 1 |
2 | Terminate a build when there has not been any log output since the last n seconds. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help_es.html: -------------------------------------------------------------------------------- 1 |
2 | Tiempo máximo especificado como segundos transcurridos desde la última traza generada. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/AbortOperation/help.html: -------------------------------------------------------------------------------- 1 |
2 | Abort the build. 3 | This is a default operation performed if no operations are specified. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/Messages_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/Messages_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help.html: -------------------------------------------------------------------------------- 1 |
2 | Writing the build description. 3 |
4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | 4 | # IntelliJ project files 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .idea 9 | 10 | # eclipse project file 11 | .settings 12 | .classpath 13 | .project 14 | build 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help-description.html: -------------------------------------------------------------------------------- 1 |
2 | A description to set. 3 | {0} will be replaced with timeout minutes. 4 |
5 | -------------------------------------------------------------------------------- /src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_13/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.447 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/Messages_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/impl/Messages_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help_es.html: -------------------------------------------------------------------------------- 1 |
2 | Escribir la descripción de la ejecución. 3 |
4 | -------------------------------------------------------------------------------- /src/test/resources/hudson/plugins/build_timeout/BuildTimeoutWrapperIntegrationTest/migrationFrom_1_12_2/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.447 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-operationList.html: -------------------------------------------------------------------------------- 1 |
2 | Actions performed when timeout occurred. 3 | If nothing specified, "Abort the build" will be used. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help-timeoutMinutes_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 設定すると、ビルドが指定した時間(最小値は3分)で完了しない場合に、自動的に中止扱いで終了します。 3 | この機能は、例えばテストで無限ループに陥った経験がある場合に役立ちます。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help.html: -------------------------------------------------------------------------------- 1 |

2 | Terminate a build based on a deadline time specified in HH:MM:SS or HH:MM (24-hour time format). 3 |

4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help.html: -------------------------------------------------------------------------------- 1 |

2 | Terminate a build based on a specified percentage of the mean of the duration of the n most recent non-failing builds. 3 |

4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/AbortOperation/help_es.html: -------------------------------------------------------------------------------- 1 |
2 | Abortar la ejecución. 3 | Ésta es la operación por defecto si no se especifica otra al terminar la ejecución. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-continueEvenFailed_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルド手順が失敗しても、続くタイムアウト時のアクションを実行します。 3 | チェックを外した場合、続くタイムアウト時のアクションは実行されず、また、ビルドが失敗とした扱いになります。 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルド手順やビルド後の処理をタイムアウト時のアクションとして実行します。
3 | すべてのビルド手順やビルド後の処理が正常に実行されることを保証するものではありません。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/Messages_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/operations/Messages_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help_es.html: -------------------------------------------------------------------------------- 1 |

2 | Abortar la ejecución según una fecha tope especificada como una hora del día en formato HH:MM:SS o HH:MM (24 horas). 3 |
4 |

-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help_es.html: -------------------------------------------------------------------------------- 1 |

2 | Definir el tiempo máximo de ejecución como un porcentaje de la duración media de las últimas n ejecuciones correctas. 3 |
4 |

-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/LikelyStuckTimeOutStrategy/help_es.html: -------------------------------------------------------------------------------- 1 |

2 | Utilizar un método heurístico basado en Executor.isLikelyStuck() para detectar si una ejecución está tardando demasiado tiempo.
3 |

-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-enabled_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 「ビルド手順の実行」をタイムアウト時のアクションに表示します。
3 | この機能は AS-IS で提供され、特定のビルド手順が正しく動作しないなどの事象があってもサポートの対象にはなりません。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/help-description_es.html: -------------------------------------------------------------------------------- 1 |
2 | La descripción a poner. 3 | "{0}" será reemplazado/a con los minutos de tiempo máximo de ejecución (timeout). 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help-timeoutPercentage_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 直近3つの失敗していないビルドの平均所要時間の指定した割合以上にビルドが続く場合、ビルドを終了させ"中止"扱いにします。 3 | 成功したビルドがない場合、"成功もしくは不安定ビルドがない場合のタイムアウト(分)"の値を使用します。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help-timeoutSecondsString_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 最後にログ出力があってからタイムアウトしたと判定するまでの秒数を指定します。 3 | 長時間ビルドで処理が行われていない場合にビルドを中止する場合に便利です。 4 | バッファリングによってログ出力は遅れることがあることに注意してください。 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/global_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/global_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/BuildTimeoutWrapper/help-operationList_es.html: -------------------------------------------------------------------------------- 1 |
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 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineTime_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ビルド開始後、ここで指定された時刻を過ぎてもビルドが完了しない場合にタイムアウト処理を行います。 3 | 指定は 24 時間表記で HH:MM もしくは HH:MM:SS のフォーマットで行ってください。 4 |
5 | 変数表記が利用可能です。 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/config_es.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-timeout-plugin/HEAD/src/main/resources/hudson/plugins/build_timeout/operations/WriteDescriptionOperation/config_es.properties -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help.html: -------------------------------------------------------------------------------- 1 |
2 | Perform a build step or a post-build action as a timeout action.
3 | This never ensure all build steps and post-build actions works correct. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/LikelyStuckTimeOutStrategy/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-continueEvenFailed.html: -------------------------------------------------------------------------------- 1 |
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 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-enabled.html: -------------------------------------------------------------------------------- 1 |
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 |
5 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/build_timeout/global/TimeOutStore.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.build_timeout.global; 2 | 3 | import java.util.concurrent.ScheduledFuture; 4 | 5 | public interface TimeOutStore { 6 | void scheduled(String key, ScheduledFuture timeOut); 7 | void cancel(String key); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/Messages.properties: -------------------------------------------------------------------------------- 1 | Descriptor.DisplayName=Terminate a build if it''s stuck 2 | 3 | Timeout.Message=Build timed out (after {0} minutes). Marking the build as {1}. 4 | Timeout.Aborted=aborted 5 | Timeout.Failed=failed 6 | 7 | BuildStepWithTimeout.DisplayName=Run with timeout 8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineToleranceInMinutes_ja.html: -------------------------------------------------------------------------------- 1 |
2 | ここで指定した時間の間であれば、デッドライン直後に開始したビルドをすぐにタイムアウトさせます。
3 | 例えばデッドラインが 13:50 の場合、本項目に 5 (分) を指定していれば、 13:52 に開始したビルドは直ちにタイムアウトします。 4 | 13:56 に開始したビルドは翌日の 13:50 をタイムアウト時刻として実行されます。 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help-timeoutSecondsString.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | /* For https://ci.jenkins.io/ */ 4 | /* The `buildPlugin` step has been provided by: https://github.com/jenkins-infra/pipeline-library */ 5 | buildPlugin(useContainerAgent: true, forkCount: '1C', configurations: [ 6 | [platform: 'linux', jdk: 25], 7 | [platform: 'windows', jdk: 21], 8 | ]) 9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help_es.html: -------------------------------------------------------------------------------- 1 |
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 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help-timeoutPercentage.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-continueEvenFailed_es.html: -------------------------------------------------------------------------------- 1 |
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 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-enabled_es.html: -------------------------------------------------------------------------------- 1 |
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 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help-timeoutMinutes_es.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/help-timeoutMinutes.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/NoActivityTimeOutStrategy/help-timeoutSecondsString_es.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineTime.html: -------------------------------------------------------------------------------- 1 |
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 |
7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates 2 | --- 3 | version: 2 4 | updates: 5 | - package-ecosystem: maven 6 | directory: / 7 | schedule: 8 | interval: weekly 9 | - package-ecosystem: github-actions 10 | directory: / 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineTime_es.html: -------------------------------------------------------------------------------- 1 |
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 |
7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-createLauncher_ja.html: -------------------------------------------------------------------------------- 1 |
2 | 「シェルの実行」「Windowsバッチコマンドの実行」などビルドノード上で外部プログラムを起動するビルド手順は、プログラムの実行のために Launcher という仕組みを使用します。 3 | デフォルトでは、タイムアウト時のアクションでは Launcher が渡されないため、これらのビルド手順の実行が失敗しますが、本項目にチェックをつけると Launcher を新規に作成してビルド手順を実行します。 4 | ビルド手順が正常に実行できる (ビルド手順が外部プログラムの実行を必要としない) のであれば、本項目にはチェックをいれないでください。 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/AbsoluteTimeOutStrategy/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.13 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/build_timeout/BuildTimeOutStrategyDescriptor.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.build_timeout; 2 | 3 | import hudson.model.Descriptor; 4 | 5 | /** 6 | * @author Nicolas De Loof 7 | */ 8 | public abstract class BuildTimeOutStrategyDescriptor extends Descriptor { 9 | public boolean isApplicableAsBuildStep() { 10 | return false; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/ElasticTimeOutStrategy/help-timeoutPercentage_es.html: -------------------------------------------------------------------------------- 1 |
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 |
7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineToleranceInMinutes.html: -------------------------------------------------------------------------------- 1 |
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 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-createLauncher.html: -------------------------------------------------------------------------------- 1 |
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 |
7 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | 3 | name: Release Drafter 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into the default branch 15 | - uses: release-drafter/release-drafter@v6 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/impl/DeadlineTimeOutStrategy/help-deadlineToleranceInMinutes_es.html: -------------------------------------------------------------------------------- 1 |
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 |
-------------------------------------------------------------------------------- /src/main/java/hudson/plugins/build_timeout/global/TimeOut.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.build_timeout.global; 2 | 3 | import jakarta.inject.Qualifier; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.Target; 6 | 7 | import static java.lang.annotation.ElementType.FIELD; 8 | import static java.lang.annotation.ElementType.METHOD; 9 | import static java.lang.annotation.ElementType.PARAMETER; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Qualifier @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) 13 | public @interface TimeOut { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/build_timeout/global/TimeOutProvider.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.build_timeout.global; 2 | 3 | import hudson.model.AbstractBuild; 4 | import hudson.model.AbstractProject; 5 | import hudson.model.BuildListener; 6 | import hudson.plugins.build_timeout.BuildTimeOutOperation; 7 | 8 | import java.time.Duration; 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | public interface TimeOutProvider { 13 | Optional timeOutFor(AbstractBuild build, BuildListener listener); 14 | 15 | List getOperations(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/build_timeout/operations/BuildStepOperation/help-createLauncher_es.html: -------------------------------------------------------------------------------- 1 |
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 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> jobType) { 49 | return true; 50 | } 51 | 52 | public static List all(Class> 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> clazz = (Class>)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> 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 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>)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 | --------------------------------------------------------------------------------