PAC Resolver

For Regular Users

This guide is for regular users to use PAC resolver for automatically resolving and embedding tasks and pipelines from local repositories, Tekton Hub, and remote URLs.

This guide explains how to use the Pipelines as Code (PAC) resolver to automatically resolve and embed tasks and pipelines from three sources: local tasks defined in your repository, remote tasks from Tekton Hub, and tasks from remote Git repositories or HTTP URLs.

TOC

Prerequisites

  • PAC component deployed and running
  • A Repository CR configured (see Configure Repository)
  • Understanding of Tekton PipelineRun structure

About PAC Resolver

The PAC resolver automatically fetches and embeds remote tasks and pipelines into your PipelineRun definitions. This eliminates the need to manually define tasks or use resolver syntax in your pipeline code.

How Task Embedding Works

When PAC resolves a task from Tekton Hub:

  1. PAC fetches the task definition (YAML) from the Hub
  2. PAC converts taskRef to taskSpec and embeds the task definition inline within your PipelineRun
  3. The embedded task becomes part of the PipelineRun definition
  4. The task doesn't need to exist as a separate Task resource in your cluster

This means you can use tasks from Tekton Hub without manually copying their definitions or creating Task resources in your cluster.

Supported Sources

  • Local Tasks: Tasks defined in your Git repository (using taskSpec or resolver syntax)
  • Tekton Hub: Tasks and pipelines from the Tekton Hub catalog
  • Remote URLs: Tasks and pipelines from remote Git repositories or HTTP URLs

Official Documentation

For comprehensive information about Pipelines as Code remote resolution features, refer to:

How PAC Resolver Works

Understanding the resolver workflow helps you troubleshoot issues and optimize your pipeline configurations.

Resolver Workflow

When PAC processes a PipelineRun with resolver annotations, it follows these steps:

  1. Event Trigger: Git event (push, pull request, etc.) triggers PAC controller
  2. Pipeline Fetch: PAC controller fetches the PipelineRun definition from your Git repository
  3. Annotation Detection: PAC controller scans annotations for resolver directives:
    • pipelinesascode.tekton.dev/task: "task-name"
    • pipelinesascode.tekton.dev/task-1: "task-name"
    • pipelinesascode.tekton.dev/pipeline: "pipeline-name"
  4. Task Resolution: For each task annotation:
    • PAC controller queries Tekton Hub API (or configured hub URL)
    • Fetches the task definition (YAML)
    • Validates the task structure
  5. Task Embedding: PAC embeds the resolved task definitions into the PipelineRun:
    • PAC converts taskRef to taskSpec and embeds the task definition inline within each task entry
    • The embedded task becomes part of the PipelineRun definition, so it doesn't need to exist as a separate Task resource in the cluster
  6. PipelineRun Creation: PAC creates the final PipelineRun with embedded tasks in Kubernetes
  7. Execution: Tekton Pipeline controller picks up the PipelineRun and executes it

Detailed Example: Step-by-Step Resolution

Let's trace through a complete example to see how resolver works:

Step 1: Original PipelineRun Definition

You define a PipelineRun in your repository (.tekton/pipelinerun.yaml):

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    pipelinesascode.tekton.dev/task: "git-clone"
spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      taskRef:
        name: git-clone
      params:
        - name: url
          value: "https://github.com/tektoncd/catalog.git"
        - name: revision
          value: "main"

Step 2: PAC Controller Processes Annotations

When a push event occurs, PAC controller:

  1. Reads the PipelineRun from Git: PAC fetches the .tekton/pipelinerun.yaml file from the repository

  2. Detects the annotation: PAC scans for task annotations like pipelinesascode.tekton.dev/task: "git-clone"

  3. Parses task name and version:

    • Task name only (e.g., "git-clone"): Fetches the latest version from Hub
    • With version (e.g., "git-clone:0.1"): Fetches the specified version
    • Version selection:
      • No version specified → PAC queries Hub for the latest stable version
      • Version specified (format: task-name:version) → PAC fetches that exact version
      • Version format follows semantic versioning (e.g., 0.1, 0.9, 1.2.3)
  4. Queries Tekton Hub API:

    • Hub URL: Defaults to cluster-internal Hub (http://tekton-hub-api.tekton-pipelines:8000/v1) or public Hub (https://api.hub.tekton.dev/v1)
    • Query for latest: PAC queries Hub for the latest available version
    • Query for specific version: PAC requests the exact version specified in the annotation
    • Example queries:
      • Latest: "git-clone" → Hub returns the newest version
      • Specific: "git-clone:0.1" → Hub returns version 0.1
  5. Receives task definition from Hub: Hub returns the complete Task YAML:

    apiVersion: tekton.dev/v1
    kind: Task
    metadata:
      name: git-clone
    spec:
      params:
      - name: url
        description: git url to clone
      - name: revision
        description: revision to checkout
      steps:
      - name: clone
        image: gcr.io/tekton-releases/git-init
        script: |
          #!/bin/sh
          git clone $(params.url) $(workspaces.output.path)
          cd $(workspaces.output.path)
          git checkout $(params.revision)

Version Selection Best Practices:

  • Production environments: Specify exact versions (e.g., "git-clone:0.1") for reproducibility and stability
  • Development/testing: Use latest version (no version suffix) to get new features and bug fixes automatically
  • Version pinning: Always pin to specific versions in production to avoid breaking changes from Hub updates
  • Version updates: Periodically review and update pinned versions in a controlled manner

Step 3: PAC Embeds Task into PipelineRun

PAC modifies the PipelineRun by converting taskRef to taskSpec and embedding the resolved task definition:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      # PAC converts taskRef to taskSpec and embeds the task definition
      taskSpec:
        params:
        - name: url
          description: git url to clone
        - name: revision
          description: revision to checkout
        steps:
        - name: clone
          image: gcr.io/tekton-releases/git-init
          script: |
            #!/bin/sh
            git clone $(params.url) $(workspaces.output.path)
            cd $(workspaces.output.path)
            git checkout $(params.revision)
      params:
        - name: url
          value: "https://github.com/tektoncd/catalog.git"
        - name: revision
          value: "main"

Step 4: PipelineRun Created in Kubernetes

PAC creates the final PipelineRun in your cluster. You can verify it:

kubectl get pipelinerun my-pipeline -n <namespace> -o yaml

Example output (abbreviated, showing embedded task):

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      # Task definition is embedded as taskSpec
      taskSpec:
        params:
        - name: url
        - name: revision
        steps:
        - name: clone
          image: gcr.io/tekton-releases/git-init
          script: |
            #!/bin/sh
            git clone $(params.url) $(workspaces.output.path)
      params:
        - name: url
          value: "https://gitlab.com/user/repo"
        - name: revision
          value: "abc1234"

Resolver Timing

Important: Task resolution happens before the PipelineRun is created in Kubernetes. This means:

  • Tasks are resolved at pipeline definition time, not at execution time
  • If a task cannot be resolved, the PipelineRun creation will fail
  • You can verify task resolution by checking the PipelineRun YAML in Kubernetes
  • Resolved tasks are cached by PAC for performance

Verifying Task Resolution

To verify that tasks were resolved correctly:

  1. Check PipelineRun in Kubernetes:

    kubectl get pipelinerun <name> -n <namespace> -o yaml

Look for embedded tasks with taskSpec within individual tasks:

spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      taskSpec:
        params:
        - name: url
        - name: revision
        steps:
        - name: clone
          image: gcr.io/tekton-releases/git-init
          script: |
            #!/bin/sh
            git clone $(params.url) $(workspaces.output.path)
      params:
        - name: url
          value: "https://gitlab.com/user/repo"
        - name: revision
          value: "abc1234"
Understanding Task Embedding

PAC embeds resolved tasks by converting taskRef to taskSpec within individual tasks. The task definition is embedded inline as part of the PipelineRun, following standard Tekton syntax.

  1. Check PAC Controller Logs:

    kubectl logs -n <pac-namespace> -l app=pipelines-as-code-controller --tail=100 | grep -i "task.*resolve"  # Replace <pac-namespace> with your actual namespace (default: tekton-pipelines)

Example output (showing task resolution):

{"level":"info","ts":"2024-01-01T12:00:00Z","logger":"controller","msg":"Resolving task","task":"git-clone","source":"hub"}
{"level":"info","ts":"2024-01-01T12:00:01Z","logger":"controller","msg":"Task resolved successfully","task":"git-clone","version":"0.9"}
{"level":"info","ts":"2024-01-01T12:00:02Z","logger":"controller","msg":"Task embedded in PipelineRun","task":"git-clone","pipelineRun":"my-pipeline"}
  1. Verify task is referenced correctly:

    # Check that taskRef.name matches the task name in annotations
    kubectl get pipelinerun <name> -n <namespace> -o jsonpath='{.spec.pipelineSpec.tasks[*].taskRef.name}'

Example output:

git-clone golangci-lint
  1. Check if PipelineRun was created successfully:

    kubectl get pipelinerun <name> -n <namespace> -o jsonpath='{.status.conditions[*].type}'

Example output:

Succeeded

If task resolution failed, the PipelineRun may not be created, or it will have a Failed condition with an error message.

Using Local Tasks

Local tasks are tasks defined directly in your Git repository. PAC supports two ways to use local tasks:

Inline Task Definition (taskSpec)

You can define tasks directly in your PipelineRun using taskSpec:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
spec:
  pipelineSpec:
    tasks:
    - name: build
      taskSpec:
        steps:
        - name: build
          image: golang:1.21
          script: |
            #!/bin/sh
            go build -o app ./cmd
    - name: test
      taskSpec:
        steps:
        - name: test
          image: golang:1.21
          script: |
            #!/bin/sh
            go test ./...

How it works:

  • Tasks are defined inline using taskSpec within each task in the pipeline
  • No external resolution is needed - tasks are part of the PipelineRun definition
  • Useful for simple, repository-specific tasks

Referencing Task Files in Repository

You can reference task files stored in your repository using PAC annotations with the special syntax for tasks within the repository.

Important: For tasks in your repository, use the annotation format with pipelinesascode.tekton.dev/task or pipelinesascode.tekton.dev/task-<N> annotations.

Repository structure:

.tekton/
├── pipelinerun.yaml
└── tasks/
    ├── build-task.yaml
    └── test-task.yaml

PipelineRun definition using PAC annotations:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    # Reference local tasks using relative paths
    pipelinesascode.tekton.dev/task: ".tekton/tasks/build-task.yaml"
    pipelinesascode.tekton.dev/task-1: ".tekton/tasks/test-task.yaml"
spec:
  pipelineSpec:
    tasks:
    - name: build
      taskRef:
        name: build-task
    - name: test
      taskRef:
        name: test-task
      runAfter: [build]

How it works:

  • PAC automatically resolves and embeds tasks from your repository when you use relative paths in task annotations
  • The task name in taskRef.name should match the task name defined in the YAML file
  • This method is simpler than using resolver: git syntax and is the recommended approach for PAC

When to Use Local Tasks

Use local tasks when:

  • Tasks are specific to your project and not suitable for sharing
  • You need full control over task definitions and versions
  • Tasks change frequently with your codebase
  • You want to keep tasks and pipelines together in version control

Using Remote Task Annotations

You can use PAC annotations to reference remote tasks from Tekton Hub or remote HTTP URLs. PAC will automatically fetch and embed these tasks into your PipelineRun.

Remote Tasks from Tekton Hub

Reference a single task from Tekton Hub:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    pipelinesascode.tekton.dev/task: "git-clone"
spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      taskRef:
        name: git-clone
      params:
        - name: url
          value: "https://github.com/tektoncd/catalog.git"
        - name: revision
          value: "main"

How it works:

  • The annotation pipelinesascode.tekton.dev/task: "git-clone" tells PAC to fetch the git-clone task from Tekton Hub
  • PAC automatically embeds the task definition into your PipelineRun
  • You can then reference it using taskRef.name: git-clone

Remote Tasks from HTTP URLs

You can also reference tasks from remote HTTP URLs:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    # Reference task from remote URL
    pipelinesascode.tekton.dev/task: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.9/git-clone.yaml"
spec:
  pipelineSpec:
    tasks:
    - name: fetch-code
      taskRef:
        name: git-clone
      params:
        - name: url
          value: "https://github.com/tektoncd/catalog.git"
        - name: revision
          value: "main"

How it works:

  • PAC fetches the task definition from the specified HTTP URL
  • PAC automatically embeds the task into your PipelineRun
  • The task name in taskRef.name should match the task name defined in the remote YAML file

Multiple Task Annotations

Reference multiple tasks using numbered annotations:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: build-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    pipelinesascode.tekton.dev/task: "git-clone"
    pipelinesascode.tekton.dev/task-1: "golangci-lint"
    pipelinesascode.tekton.dev/task-2: "buildah"
spec:
  pipelineSpec:
    tasks:
    - name: fetch
      taskRef:
        name: git-clone
      params:
        - name: url
          value: "https://github.com/tektoncd/catalog.git"
        - name: revision
          value: "main"
    - name: lint
      taskRef:
        name: golangci-lint
      runAfter: [fetch]
    - name: build
      taskRef:
        name: buildah
      runAfter: [lint]

Task List Syntax

You can also use bracket syntax to specify multiple tasks in a single annotation:

metadata:
  annotations:
    pipelinesascode.tekton.dev/task-1: "[golangci-lint, buildah]"

This is equivalent to:

metadata:
  annotations:
    pipelinesascode.tekton.dev/task-1: "golangci-lint"
    pipelinesascode.tekton.dev/task-2: "buildah"

Task Version Specification

By default, PAC fetches the latest version of a task from Hub. To specify a specific version, use the format task-name:version.

Reference: For more details on remote task resolution, see Red Hat OpenShift Pipelines as Code documentation.

Latest version (recommended for development):

metadata:
  annotations:
    pipelinesascode.tekton.dev/task: "git-clone"

Specific version (recommended for production):

metadata:
  annotations:
    pipelinesascode.tekton.dev/task: "git-clone:0.9"

Multiple tasks with versions:

metadata:
  annotations:
    pipelinesascode.tekton.dev/task: "git-clone:0.9"
    pipelinesascode.tekton.dev/task-1: "golangci-lint:0.4"
    pipelinesascode.tekton.dev/task-2: "buildah"  # Uses latest

Custom Hub URL

The default hub-url points to the cluster-internal Tekton Hub service in the default namespace (http://tekton-hub-api.tekton-pipelines:8000/v1). If Tekton Hub is deployed in a different namespace, adjust the namespace in the URL accordingly. If you need to use a different Hub instance, configure it in the OpenShiftPipelinesAsCode CR:

apiVersion: operator.tekton.dev/v1alpha1
kind: OpenShiftPipelinesAsCode
metadata:
  name: pipelines-as-code
spec:
  settings:
    # For cluster-internal Hub in different namespace
    hub-url: "http://tekton-hub-api.<your-namespace>:8000/v1"
    
    # Or for external/public Hub
    hub-url: "https://api.hub.tekton.dev/v1"
    
    # Or for custom Hub instance
    hub-url: "https://custom-hub.example.com/v1"

Note: Only the PAC controller needs access to the Hub URL. If using a cluster-internal Hub, ensure the PAC controller can reach the Hub service.

Using Remote Pipeline Annotations

Limited Use Case

Remote pipeline annotations are rarely used in practice. Most users define pipelines inline using pipelineSpec rather than referencing remote pipelines. This section is included for completeness.

You can reference remote pipelines from Tekton Hub, though this is less common than using inline pipeline definitions:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    # Reference remote pipeline from Tekton Hub
    pipelinesascode.tekton.dev/pipeline: "pipeline-name"
spec:
  pipelineRef:
    name: pipeline-name
  params:
  - name: image-url
    value: "registry.example.com/myapp"

How it works:

  • The annotation pipelinesascode.tekton.dev/pipeline: "pipeline-name" tells PAC to fetch the pipeline from Tekton Hub
  • PAC automatically embeds the pipeline definition
  • You reference it using pipelineRef.name

Note: In most cases, you should define your pipeline inline using pipelineSpec in your repository, rather than using remote pipelines. This gives you better version control and visibility of your pipeline definitions.

Combining Remote Tasks and Pipelines

Comparison with Resolver Syntax

PAC annotations provide a simpler alternative to Tekton's resolver syntax:

metadata:
  annotations:
    pipelinesascode.tekton.dev/task: "git-clone"
spec:
  pipelineSpec:
    tasks:
    - name: clone
      taskRef:
        name: git-clone

Using Resolver Syntax

spec:
  pipelineSpec:
    tasks:
    - name: clone
      taskRef:
        resolver: hub
        params:
        - name: name
          value: git-clone
        - name: kind
          value: task

Advantages of PAC annotations:

  • Simpler syntax
  • Automatic task embedding
  • No need to specify resolver parameters
  • Works seamlessly with PAC's task resolution

Troubleshooting

Task Not Found

  1. Verify task name: Check that the task name is correct in Tekton Hub

  2. Check Hub URL: Verify the hub URL is configured correctly

  3. Review PAC logs:

    kubectl logs -n <pac-namespace> -l app=pipelines-as-code-controller --tail=100 | grep -i task

Example output:

{"level":"info","ts":"2024-01-01T12:00:00Z","logger":"controller","msg":"Resolving task","task":"git-clone","source":"hub"}
{"level":"info","ts":"2024-01-01T12:00:01Z","logger":"controller","msg":"Task resolved successfully","task":"git-clone","version":"0.9"}
{"level":"info","ts":"2024-01-01T12:00:02Z","logger":"controller","msg":"Task embedded in PipelineRun","task":"git-clone","pipelineRun":"my-pipeline"}

Task Resolution Fails

  1. Check network connectivity: Ensure PAC controller can reach Tekton Hub

    # Test Hub connectivity from PAC controller pod
    kubectl exec -n <pac-namespace> \
      $(kubectl get pod -n <pac-namespace> -l app=pipelines-as-code-controller -o jsonpath='{.items[0].metadata.name}') \
      -- curl -I https://api.hub.tekton.dev/v1/resource/task/git-clone

Example output (if accessible):

HTTP/1.1 200 OK
Content-Type: application/json
  1. Verify Hub configuration: Check the hub-url setting in OpenShiftPipelinesAsCode CR

    kubectl get openshiftpipelinesascodes.operator.tekton.dev pipelines-as-code -o jsonpath='{.spec.settings.hub-url}'

Example output:

http://tekton-hub-api.tekton-pipelines:8000/v1
  1. Review task version: Ensure the specified version exists

    # Query Tekton Hub for available versions
    curl https://api.hub.tekton.dev/v1/resource/task/git-clone

Example output (abbreviated):

{
  "id": 1,
  "name": "git-clone",
  "kind": "Task",
  "latestVersion": {
    "id": 1,
    "version": "0.9"
  },
  "versions": [
    {"version": "0.9"},
    {"version": "0.8"},
    {"version": "0.7"}
  ]
}

Task Not Embedded

  1. Verify annotation syntax: Check annotation key and value format
  2. Check PipelineRun: Ensure taskRef.name matches the task name in annotation
  3. Review PAC controller logs for embedding errors

Next Steps