Jenkins Templating Engine: Library Binding Issue

# Jenkins Templating Engine: Library Binding Issue

## Problem Summary

JTE successfully loads libraries but templates cannot access them. Getting `MissingPropertyException: No such property: docker for class: WorkflowScript` despite logs showing `[JTE] Loading Library docker` succeeded.

## Environment

- **Jenkins Version**: 2.504.3 (also tested on CloudBees CI Managed Controller 2.492.1.3-rolling)

- **JTE Plugin Version**: 2.5.5 (Templating Engine)

- **Setup Type**: Multibranch Pipeline with Jenkins Templating Engine

- **Git Platform**: Azure DevOps (issue confirmed on GitHub as well)

- **Issue Confirmed On**: Two separate Jenkins instances with same results

## Repository Structure

### Template/Library Repository (jte-library-repo)

```

jte-library-repo/

├── templates/

│ ├── Jenkinsfile # Default template

│ ├── static-docker-ecr/

│ │ └── Jenkinsfile

│ └── node-docker-ecr/

│ └── Jenkinsfile

└── libraries/

├── docker/

│   └── steps/

│       └── buildImage.groovy

└── ecr/

    └── steps/

        └── push.groovy

```

### Application Repository (simple-test-app)

```

simple-test-app/

├── pipeline_config.groovy

├── Dockerfile

└── index.html

```

## Steps to Reproduce

### 1. Create Template/Library Repository

Create a Git repository named `jte-library-repo` with this structure:

```

jte-library-repo/

├── templates/

│ └── Jenkinsfile

└── libraries/

└── docker/

    └── steps/

        └── buildImage.groovy

```

**File: templates/Jenkinsfile**

```groovy

node {

stage("Checkout") {

    checkout scm

}

stage("Docker Build") {

    docker.buildImage()

}

}

```

**File: libraries/docker/steps/buildImage.groovy**

```groovy

void call() {

echo "\[Docker\] Building image: ${config.image}:${config.tag}"

}

```

### 2. Create Application Repository

Create a Git repository named `simple-test-app` with:

```

simple-test-app/

├── pipeline_config.groovy

└── Dockerfile

```

**File: pipeline_config.groovy**

```groovy

libraries {

docker {

image = "test-app"

tag = "1.0"

}

}

```

**File: Dockerfile**

```dockerfile

FROM alpine:latest

CMD [“echo”, “Hello”]

```

### 3. Configure Jenkins Global JTE Settings

Go to: **Manage Jenkins → Configure System → Jenkins Templating Engine**

Add Pipeline Configuration:

- Source: From SCM → Git

- Repository: [URL to jte-library-repo]

- Configuration Base Directory: `templates`

Add Library Source:

- Name: `jte-library-repo`

- Source: From SCM → Git

- Repository: [URL to jte-library-repo]

- Library Path: `libraries`

### 4. Create Multibranch Pipeline Job

1. New Item → Multibranch Pipeline

2. Branch Sources → Add Git source → [URL to simple-test-app]

3. Build Configuration:

- Mode: **Jenkins Templating Engine**

- Pipeline Configuration Path: `pipeline_config.groovy`

4. Save

### 5. Run Build

Click “Build Now” on the controller branch.

### Expected Result

```

[JTE] Loading Library docker

[Pipeline] stage (Docker Build)

[Docker] Building image: test-app:1.0

```

### Actual Result

```

[JTE] Loading Library docker ✓

[Pipeline] stage (Docker Build)

ERROR: No such property: docker for class: WorkflowScript

```

## Configuration

### Global Jenkins Configuration

**Manage Jenkins → Configure System → Jenkins Templating Engine**

```

Pipeline Configuration:

Source Location: From SCM

SCM: Git

Repository: https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

Credentials: git-credentials

Branches to build: \*/master

Configuration Base Directory: templates

Library Sources:

Name: jte-library-repo

Source Location: From SCM

SCM: Git

Repository: https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

Credentials: git-credentials

Branches to build: \*/master

Library Path: libraries

```

### Job Configuration

**simple-test-app → Configure → Build Configuration**

```

Mode: Jenkins Templating Engine

Advanced:

Pipeline Template Path: (empty or various values tried)

Pipeline Configuration Path: pipeline_config.groovy

:check_box_with_check: Exclude branches without a pipeline configuration file

```

### Application Configuration

**File: simple-test-app/pipeline_config.groovy**

```groovy

template = “static-docker-ecr”

libraries {

docker {

image = "simple-test-app"

tag = "${env.BRANCH_NAME ?: 'main'}-${env.BUILD_NUMBER ?: 'latest'}"

}

ecr {

registry = "YOUR_AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com"

repository = "simple-test-app"

region = "us-east-1"

tag = "${env.BRANCH_NAME ?: 'main'}-${env.BUILD_NUMBER ?: 'latest'}"

image = "simple-test-app"

}

}

```

### Template File

**File: jte-library-repo/templates/Jenkinsfile**

```groovy

// JTE Default Template

// Executed as a JTE template with full library access

node {

stage("Checkout") {

    checkout scm

}



stage("Docker Build") {

    docker.buildImage()  // FAILS HERE WITH MissingPropertyException

}



stage("Push to ECR") {

    ecr.push()

}

}

```

### Library Step

**File: jte-library-repo/libraries/docker/steps/buildImage.groovy**

```groovy

void call() {

echo "\[Docker\] Building image: ${config.image}:${config.tag}"

sh """

    docker build -t ${config.image}:${config.tag} .

"""

echo "\[Docker\] Image built successfully: ${config.image}:${config.tag}"

}

```

## Actual Build Output

```

Started by user Srikanth Mamidala

[JTE] templates/pipeline_config.groovy does not exist.

[JTE] – scm: git https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

[JTE] Obtained Template Configuration File

[JTE] – scm: git Azure DevOps Services | Sign In

[JTE] – file path: pipeline_config.groovy

[JTE] Pipeline Configuration Modifications

[JTE] Configurations Added:

[JTE] - template set to static-docker-ecr

[JTE] - libraries.docker.image set to simple-test-app

[JTE] - libraries.docker.tag set to controller-53

[JTE] - libraries.ecr.registry set to YOUR_AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com

[JTE] - libraries.ecr.repository set to simple-test-app

[JTE] - libraries.ecr.region set to us-east-1

[JTE] - libraries.ecr.tag set to controller-53

[JTE] - libraries.ecr.image set to simple-test-app

[JTE] Obtained Template

[JTE] – scm: git https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

[JTE] – file path: templates/Jenkinsfile

[JTE] Loading Library docker ✓

[JTE] – scm: git https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

[JTE] Loading Library ecr ✓

[JTE] – scm: git https://your-company.visualstudio.com/DefaultCollection/YOUR_ORG/_git/jte-library-repo

[Pipeline] Start of Pipeline

[Pipeline] node

Running on platform-linux-static-pod-eks in /home/jenkins/agent/workspace/simple-test-app_controller

[Pipeline] {

[Pipeline] stage

[Pipeline] { (Checkout)

[Pipeline] checkout

✓ Checkout successful

[Pipeline] }

[Pipeline] // stage

[Pipeline] stage

[Pipeline] { (Docker Build)

[Pipeline] }

[Pipeline] // stage

[Pipeline] }

[Pipeline] // node

[Pipeline] End of Pipeline

ERROR: groovy.lang.MissingPropertyException: No such property: docker for class: WorkflowScript

at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:66)

at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:471)

\[... stack trace continues ...\]

Finished: FAILURE

```

## The Issue

**Contradiction in behavior:**

- :white_check_mark: Logs show: `[JTE] Loading Library docker` and `[JTE] Loading Library ecr`

- :white_check_mark: Libraries successfully loaded from jte-library-repo repository

- :white_check_mark: Library step files exist and are accessible

- ✗ Template execution fails: `No such property: docker for class: WorkflowScript`

- ✗ Library objects (docker, ecr) are not accessible in template

## What We’ve Tried

### 1. Multiple Template Approaches

**Subdirectories with Named Templates:**

```

templates/

├── static-docker-ecr/Jenkinsfile

└── node-docker-ecr/Jenkinsfile

```

With `template = “static-docker-ecr”` in pipeline_config.groovy.

- :cross_mark: JTE couldn’t find templates at this path

- Pipeline Template Path field in job config appears mandatory but ignores these values

**Dispatcher/Router Pattern:**

Created `templates/Jenkinsfile` as a router:

```groovy

def templateName = pipelineConfig.template

def templatePath = “templates/${templateName}/Jenkinsfile”

node {

checkout(\[

    $class: 'GitSCM',

    branches: \[\[name: '\*/master'\]\],

    userRemoteConfigs: \[\[url: 'https://...jte-library-repo'\]\]

\])

load(templatePath)

}

```

- :white_check_mark: Router loaded successfully

- :cross_mark: When using `load()`, the loaded template lost access to JTE library bindings

- Error: `No such property: docker` even though libraries loaded

**Single Default Template:**

Simplified to single `templates/Jenkinsfile`:

```groovy

node {

stage("Checkout") { checkout scm }

stage("Docker Build") { docker.buildImage() }

}

```

- :white_check_mark: Template found and loaded

- :white_check_mark: Libraries load: `[JTE] Loading Library docker`

- :cross_mark: Still fails: `No such property: docker`

### 2. Job Configuration Variations

**Pipeline Template Path Field:**

The job configuration field “Pipeline Template Path” appears mandatory (won’t accept empty value). Tried:

- `templates/Jenkinsfile` :cross_mark:

- `Jenkinsfile` :cross_mark:

- `static-docker-ecr/Jenkinsfile` :cross_mark:

- `${template}` (variable substitution) :cross_mark:

- Leaving empty (Jenkins fills with default) :cross_mark:

None resolved the library binding issue.

### 3. Configuration Directory Variations

**Global Configuration Base Directory:**

- `templates` :white_check_mark: (finds templates)

- Empty/blank :cross_mark: (templates not found)

- Root level `/` :cross_mark: (templates not found)

**Template Locations:**

- `Jenkinsfile` at repository root :cross_mark: (executes as regular pipeline, no JTE bindings)

- `templates/Jenkinsfile` :white_check_mark: (finds template but libraries not accessible)

- `templates/subdirectory/Jenkinsfile` :cross_mark: (template not found by default)

### 4. Library Configuration

- :white_check_mark: Verified library path: `libraries/docker/steps/buildImage.groovy`

- :white_check_mark: Confirmed libraries load in build logs

- :white_check_mark: Tried different library structures (flat vs nested)

- :white_check_mark: Removed global pipeline_config.groovy (was initially blocking library loading)

- :white_check_mark: Libraries show as loaded but remain inaccessible in template execution

### 5. Template Execution Context

- :white_check_mark: Added `node` blocks (required for workspace)

- :white_check_mark: Verified template loads from correct repository

- :white_check_mark: Confirmed logs show: `[JTE] Obtained Template: templates/Jenkinsfile`

- :cross_mark: Library objects still not accessible despite successful loading

**The Core Issue:** Libraries consistently load successfully (confirmed in logs) but the binding that makes them accessible as objects (`docker`, `ecr`) in templates never materializes. This suggests either a configuration we’re missing or a bug in how JTE provides library bindings to template execution context.

## Questions

### 1. Library Binding Issue

Why do libraries load successfully (confirmed in logs) but aren’t accessible as objects in the template execution context?

**Expected:**

```groovy

docker.buildImage() // Should work after [JTE] Loading Library docker

```

**Actual:**

```

MissingPropertyException: No such property: docker

```

### 2. Multiple Templates Support

What is the correct way to support multiple named templates in a single governance tier?

We want applications to select templates via:

```groovy

template = “static-docker-ecr” // or “node-docker-ecr”

```

But JTE appears to only find default template at `templates/Jenkinsfile`.

### 3. Correct Template Structure

Should templates be:

- `templates/template-name/Jenkinsfile` (subdirectories)

- `templates/template-name.Jenkinsfile` (flat files)

- Something else?

### 4. Library Object Access

Should library objects be directly accessible in templates as `docker.buildImage()` or is there a different calling convention required?

## Goal

Enterprise setup with:

- Centralized governance (jte-library-repo)

- Multiple templates for different app types

- Shared, reusable libraries

- Applications select templates via pipeline_config.groovy

## Additional Context

- Using Multibranch Pipeline jobs

- JTE mode enabled in job configuration

- Libraries load in logs but binding not available during template execution

- Issue occurs with both Azure DevOps and GitHub

- This is a fundamental JTE configuration issue, not platform-specific

Any guidance on proper configuration for this setup would be greatly appreciated!

Jenkins setup: