This is a Jenkins plugin that allows the building of simple but powerful rules to define which builds should be removed from the history and which ones should be preserved.
The rules use conditionals to filter (select) completed builds from the build history and actions to operate on the builds selected by the conditionals.
Users can add Build History Manager rules to Jenkins jobs. The rules are composed of three types of objects:
- Built-in conditions that control the applications of rules to builds,
- Optional Conditions that are ANDed together to filter (select) builds,
- Optional Actions that are applied to builds when all their rule's conditions are met.
The plugin has three built-in conditions that control the flow of operations. Users cannot remove these conditions. The first one is built-in to the plugin for all rules, and the other two are configurable on a per-rule basis.
The built-in conditions are:
- A global check for the "Keep this build forever" state, and when it returns true, rules are not applied to the build. This currently cannot be controlled nor configured by the user.
- A per-rule
matchAtMost
counter (Process this rule at most (times)
in the UI) that limits the number of times a rule can be applied (default is-1
, meaning there is no limit). - A per-rule
continueAfterMatch
boolean (Proceed to the next rule if the conditions of this rule are met
in the UI) that causes the plugin to apply the next rule to the same build after the current rule has been applied (default istrue
, meaning to continue to apply rules to the build being processed).
Users can add a list of Conditions to each rule, in any order they need. The conditions are checked in the order they are defined.
The conditions are:
Providing the built-in conditions allow, the optional condition checks have the following effects:
- As soon as one of the conditions does not match, the plugin ignores the rule's Actions.
- When all the conditions of the rule are met, the plugin applies the rule's Actions.
- When no optional conditions are specified, the plugin automatically applies the rule's Actions.
Users can add a list of Actions to each rule, in any order they need. The actions are applied in the order they are defined.
The actions are:
If the first action is to delete the build, the other actions will still be applied but have no real effect.
The plugin starts by initializing the internal match counters for each rule to zero.
The plugin then loops through all the completed builds in the build history, starting from the most recent, and processes each build with possibly every rule (depending on the conditions) by looping through the rule list once for each completed build.
- For each completed build, the following happens:
- If the build is marked as keep forever, the build is ignored and the loop moves on to the next completed build.
- For each rule, the following happens to the current build:
- If the "rule match counter" equals the
matchAtMost
value, stop processing the current rule and move on to the next rule (next iteration of "for each rule") - If there are no optional conditions, or if all the optional conditions are matched, the following happens:
- The rule counter is incremented by one.
- All the actions are performed.
- If
continueAfterMatch
istrue
, the next rule is applied to the same build, and goes to the next iteration of the "for each rule" loop. - If
continueAfterMatch
isfalse
, the plugin stops applying rules to this build, and goes to the next iteration of the "for each completed build" loop.
- If one or more optional conditions are not met, the build continues to the next rule (next iteration of the "for each rule" loop).
- If the "rule match counter" equals the
Notes:
- If the
matchAtMost
value is set to zero, the rule is effectively disabled. This is useful if the user wants to disable a rule while keeping its other configuration values. - Once the
matchAtMost
value is reached, the rule is effectively disabled and is no longer applied. - It may not make sense to continue to apply rules after a build is deleted, but the plugin handles this case gracefully.
- Having no condition is a way to unconditionally apply actions to builds, for example to delete all the builds. Use it wisely.
- Having no action is a way to ignore builds and keep them in the build history.
By using conditions and actions, it becomes straightforward to achieve a number of scenarios, including:
- Delete unstable or aborted builds from the build history if they do not provide any value.
- Keep only the last builds depending on their result, so the history contains the most recent builds with the specified result(s): aborted, unstable, not built, failure, or success.
- Keep builds only from
master
branch if the project builds all branches including feature branches - Remove any builds with a build number lower than the specified value to easily discard all old builds at once.
The following configuration allows to save the last 5 builds, while deleting the rest of the build history:
The following configuration has two rules.
The first rule ensures that the latest build with a failure
result
is not deleted. The second rule deletes all builds which are not success
.
In other words, it keeps the most recent broken build and all stable builds.
pipeline {
agent any
options {
buildDiscarder(BuildHistoryManager([
[
conditions: [
BuildResult(matchFailure: true)
],
matchAtMost: 1,
continueAfterMatch: false
],
[
conditions: [
BuildResult(matchNotBuilt: true, matchAborted: true, matchFailure: true, matchUnstable: true)
],
actions: [DeleteBuild()]
]
]))
}
stages {
stage('Demo') {
steps {
echo "Hello!"
}
}
}
}
The following configuration has three rules.
The first rule uses the token macro condition to test the value of a parameter.
It removes builds where the string value of ENABLE_HISTORY
is "false".
The second rule preserves the most recent 24 builds that do not match the first rule.
The third rule deletes the remaining build.
Consequently, these three rules work together to preserve the last 24 builds where ENABLE_HISTORY
is true.
pipeline {
agent any
options {
buildDiscarder(BuildHistoryManager([
[
conditions: [
TokenMacro(template: '"${ENABLE_HISTORY}"', value: '"false"')
],
actions: [DeleteBuild()],
continueAfterMatch: false
],
[
matchAtMost: 24,
continueAfterMatch: false
],
[
actions: [DeleteBuild()]
]
]))
}
parameters {
booleanParam(
name: 'ENABLE_HISTORY',
defaultValue: true,
description: 'Check to preserve build.'
)
}
stages {
stage('Demo') {
steps {
echo "Hello!"
}
}
}
}
Please refer to the Wiki for more detailed information. Additionally, make sure to review the provided guidance on avoiding issues while creating rules.
It is possible to create complex rules with multiple conditions and actions. Each rule can define multiple conditions and actions. The plugin entry point is the BuildHistoryManager class, which extends from the Jenkins core BuildDiscarder class. The Rule.perform() method serves as the core function responsible for processing conditions and actions.
The plugin is called by the Jenkins core when the build is completed. It is not tied to any particular run such as the last completed run, which could potentially be deleted by certain actions. To assist with troubleshooting and analysis, the plugin logs helpful messages to the Jenkins logs.
For debugging purposes, you can use the ChangeBuildDescriptionAction action. This action allows you to update the build description, making it convenient to test and debug conditions before applying actual deletions as actions.
Once you have developed a new feature or improvement, it is essential to conduct thorough testing by implementing multiple unit or integration tests. This ensures the reliability and functionality of the implemented changes.
Please refer to the release notes for the changelog and specific details about the changes made in each version.
If you come across an issue, you can contribute by either sending a pull request to resolve it or filing a bug report.
This applies similarly if you come across a missing Action
or Condition
.
In addition, it is important to remember the following steps:
- Conduct tests on your local Jenkins instance to ensure the changes work as expected.
- Include new unit tests following the given -> when -> then approach to verify the behavior of the changes.
- Remember to perform integration tests to ensure the changes integrate smoothly with the overall system.
- Update the wiki documentation to reflect the changes made.