Jenkins (Groovy) CI/CD Pipeline Guidelines

Jenkins Groovy Style

  • Use four-space indentation, braces and no semicolons.
  • Use explicit types for variables, parameters, return values, closure parameters and collection elements.
  • Prefer String, boolean, int, long, List<T>, Set<T>, Map<K, V> and Closure where applicable.
  • Use wrapper types such as Boolean or Integer only when null is meaningful.
  • Use def only for genuinely dynamic Jenkins API objects.
  • Use camelCase for variables, methods and parameters; UpperCamelCase for classes; and UPPER_SNAKE_CASE for constants.
  • Use descriptive Boolean names such as shouldDeploy and imageExists.
  • Use single quotes for plain strings and double quotes only when interpolation is required.
  • Keep methods small and focused.
  • Extract duplicated behavior within one Jenkinsfile into typed helper methods.
  • Move behavior reused across Jenkinsfiles to a Jenkins Shared Library.
  • Keep the Jenkinsfile focused on orchestration; place substantial build, parsing and processing logic in project scripts or build tools.
  • Prefer simple for loops when invoking pipeline steps repeatedly.
  • Avoid complex Groovy collection operations around pipeline steps.
  • Values that remain in use across pipeline steps must be serializable.
  • Do not keep non-serializable objects such as iterators, streams or matchers for use after a pipeline step.
  • Use an explicit for loop and capture the current value in a local variable when constructing parallel pipeline branches. This avoids variable-scoping issues and reduces the risk of CPS method mismatches.
  • Avoid @NonCPS unless required. An @NonCPS method must not invoke pipeline steps.
  • Do not share mutable state between parallel branches.
  • Do not override standard pipeline steps or access Jenkins internals directly.
  • Pass credentials and user-controlled values through environment variables; never interpolate them into Groovy command strings.
  • Use returnStatus: true only when the exit code is handled explicitly.
  • Unexpected failures must fail or abort the build.
  • Catch exceptions only to retry transient failures, add context and rethrow or perform cleanup without masking the original build result.
  • Comment lifecycle decisions and exceptions, not self-explanatory code.

Resource Lifecycle

  • Every node, ws or equivalent workspace allocation must clean its workspace in a local finally block. (See onNodeWithTemporaryWorkspace)
  • Cleanup must run on the same node and in the same workspace context in which the resource was created.
  • Parallel branches must own and clean their resources independently.
  • A locked critical section whose node label resolves to exactly one target server may clean that target later. Cleanup must still run in finally.
  • Temporary Docker resources must have targeted immediate cleanup and ownership labels that allow abandoned resources to be identified by host level fallback cleanup. Build owned resources use ci.owner=jenkins, ci.job and ci.build labels. Add a ci.resource label when a resource type needs to be distinguished.
  • Every temporary Docker image must be registered for pipeline cleanup before creation.
  • Temporary containers and their temporary volumes must be removed together when their lifecycle ends.
  • Build specific cleanup must be targeted and idempotent. Broad Docker prune commands must not run from the Jenkins pipelines. Broader host level retention belongs to infrastructure managed cleanupdata and must have an explicit scope and retention policy.
  • Cleanup failures must be logged without masking the original build result or swallowing an abort.

Performance

Every pipeline change must be reviewed for its effect on runtime and controller or agent resource usage.

Avoid:

  • broad locks that serialize independent work
  • expensive computation or large data processing in pipeline Groovy
  • repeated checkouts, builds, Docker image pulls or dependency installations
  • unnecessary repeated cleanup or broad filesystem and Docker scans
  • restricting work to specific agents without justification and documentation
  • excessive logging, retries, polling, network calls or large stash operations

Expensive work should run once, be narrowly scoped and be reused where safe.
Changes affecting expensive operations, lock scope, agent selection, caching, retries or large data transfers must be investigated for their runtime and resource impact.