私はJenkinsとMultibranch Pipelineを使用します。アクティブなgitブランチごとに仕事があります。新しいビルドは、gitリポジトリのプッシュによってトリガーされます。私が望んでいるのは、同じブランチに新しいビルドが現れた場合、現在のブランチで実行中のビルドを中止することです。
例:ブランチfeature1
にコミットしてプッシュします。その後、BUILD_1
がJenkinsで開始されました。 feature1
の実行中に、別のコミットを行い、ブランチBUILD_1
にプッシュします。 BUILD_1
を中止し、BUILD_2
を開始したい。
stage concurrency=x
オプションと stage-lock-milestone 機能を使用しようとしましたが、問題を解決できませんでした。
また、私はこのスレッドを読みました 新しいものが開始された場合にJenkinsジョブを停止します 、しかし、私の問題の解決策はありません。
これに対する解決策を知っていますか?
Execute concurrent builds if necessary
を使用してプロジェクトのジョブ並列実行を有効にします
最初のビルドステップとしてexecute system groovy script
を使用します。
import hudson.model.Result
import jenkins.model.CauseOfInterruption
//iterate through current project runs
build.getProject()._getRuns().iterator().each{ run ->
def exec = run.getExecutor()
//if the run is not a current build and it has executor (running) then stop it
if( run!=build && exec!=null ){
//prepare the cause of interruption
def cause = { "interrupted by build #${build.getId()}" as String } as CauseOfInterruption
exec.interrupt(Result.ABORTED, cause)
}
}
中断されたジョブにはログがあります:
Build was aborted
interrupted by build #12
Finished: ABORTED
Jenkins Pipeline Multibranchで必要な場合は、Jenkinsfileで次のように実行できます。
def abortPreviousRunningBuilds() {
def hi = Hudson.instance
def pname = env.JOB_NAME.split('/')[0]
hi.getItem(pname).getItem(env.JOB_BASE_NAME).getBuilds().each{ build ->
def exec = build.getExecutor()
if (build.number != currentBuild.number && exec != null) {
exec.interrupt(
Result.ABORTED,
new CauseOfInterruption.UserInterruption(
"Aborted by #${currentBuild.number}"
)
)
println("Aborted previous running build #${build.number}")
} else {
println("Build is not running or is current build, not aborting - #${build.number}")
}
}
}
Jenkinsスクリプトセキュリティでは、ホワイトリストに登録されていない方法を使用しているため、ここでのソリューションの多くは困難になります。
Jenkinsfileの開始時にこれらのマイルストーンの手順を使用して、これは私のために働いています:
def buildNumber = env.BUILD_NUMBER as int
if (buildNumber > 1) milestone(buildNumber - 1)
milestone(buildNumber)
結果は次のようになります。
グローバル共有ライブラリに次のスクリプトを含めることで動作するようになりました:
import hudson.model.Result
import jenkins.model.CauseOfInterruption.UserInterruption
def killOldBuilds() {
while(currentBuild.rawBuild.getPreviousBuildInProgress() != null) {
currentBuild.rawBuild.getPreviousBuildInProgress().doKill()
}
}
そして、私のパイプラインでそれを呼び出す:
@Library('librayName')
def pipeline = new killOldBuilds()
[...]
stage 'purge'
pipeline.killOldBuilds()
編集:oldBuildをどれだけ強力に強制終了するかに応じて、doStop()、doTerm()、またはdoKill()を使用できます。
@ C4storのアイデアに基づいて、私はこの改善されたバージョンを作成しました... @daggettのバージョンからより読みやすくなりました
import hudson.model.Result
import hudson.model.Run
import jenkins.model.CauseOfInterruption.UserInterruption
def abortPreviousBuilds() {
Run previousBuild = currentBuild.rawBuild.getPreviousBuildInProgress()
while (previousBuild != null) {
if (previousBuild.isInProgress()) {
def executor = previousBuild.getExecutor()
if (executor != null) {
echo ">> Aborting older build #${previousBuild.number}"
executor.interrupt(Result.ABORTED, new UserInterruption(
"Aborted by newer build #${currentBuild.number}"
))
}
}
previousBuild = previousBuild.getPreviousBuildInProgress()
}
}
また、以前のバージョンからいくつかのマイナーな調整を加えたバージョンをコンパイルしました。
while()
ループは、ビルドごとに複数の出力を生成しましたdef killOldBuilds(userAborting) {
def killedBuilds = []
while(currentBuild.rawBuild.getPreviousBuildInProgress() != null) {
def build = currentBuild.rawBuild.getPreviousBuildInProgress()
def exec = build.getExecutor()
if (build.number != currentBuild.number && exec != null && !killedBuilds.contains(build.number)) {
exec.interrupt(
Result.ABORTED,
// The line below actually requires a userId, and doesn't output this text anywhere
new CauseOfInterruption.UserInterruption(
"${userAborting}"
)
)
println("Aborted previous running build #${build.number}")
killedBuilds.add(build.number)
}
}
}
特定のブランチからビルドを中止し、別のブランチからの他のビルドを同じジョブで実行できるようにする方法はありますか。たとえば、Branch1とBranch2をジョブで実行しているとします。最新のビルドを除く、Branch1から現在実行中のすべてのビルドを中止できると同時に、Branch2がビルドの実行を開始し、別のブランチであるためBranch2がビルドを実行できるようにしたいと考えています。出来ますか?
明確にするために;多くのブランチがあるので、同時ビルドを防止したり、次のビルドが始まるとすぐに最後をキャンセルしたりすることはできません。どのような方法を使用する場合でも、ブランチがジョブを実行しているかどうかを確認する必要があります。すでに実行されています。コードを実行すると、Jenkinsでシステムgroovyが実行されます。
import hudson.model.Result
import jenkins.model.CauseOfInterruption
import groovy.transform.Field
import jenkins.model.*
build.getProject()._getRuns().iterator().each{ run ->
def exec = run.getExecutor()
//from each run get the branch_name and put it into the list, add it to the list
def branchName = build.environment.get("GIT_BRANCH")
def list = []
list.add(branchName)
for (i = 0; i <list.size(); i++) {
if( run!=build && exec!=null && branchName == list[i]){
exec.interrupt(Result.ABORTED)
}
}
}