维护 Pipeline 代码

面向普通用户

本指南面向普通用户,用于在 Git 仓库中创建和维护 pipeline 定义。

本指南说明如何使用 PAC 在源代码仓库中维护 pipeline 定义。

Pipeline 文件位置

PAC 会在仓库中的特定位置查找 pipeline 定义:

默认位置

默认位置是仓库根目录下的 .tekton/pipelinerun.yaml

your-repo/
├── .tekton/
│   └── pipelinerun.yaml
├── src/
└── README.md

多个 Pipeline 文件

你可以将 pipeline 组织在多个文件中:

.tekton/
├── pipelinerun.yaml          # Main pipeline
├── test-pipeline.yaml        # Test pipeline
└── deploy-pipeline.yaml      # Deploy pipeline

PAC 会处理 .tekton/ 目录下所有 .yaml.yml 文件。

多个文件中的多个 PipelineRun

当你在不同文件中有多个 PipelineRun 定义时:

  • 每个 PipelineRun 都会独立评估
  • 多个 PipelineRun 可以匹配同一个事件(它们会并行运行)
  • 每个 PipelineRun 必须具有唯一的注解,以控制其触发时机
  • 使用具有描述性的文件名来组织不同类型的 pipeline(例如,test-pipeline.yamldeploy-pipeline.yaml

示例:如果你同时有 test-pipeline.yamldeploy-pipeline.yaml,并且它们都匹配到 main 分支的 push 事件,那么这两个 pipeline 都会并行运行。

Pipeline 定义结构

PAC pipeline 是一个标准的 Tekton PipelineRun 资源,并带有 PAC 特定的注解。

理解 Tekton 资源
  • PipelineRun:用于执行 pipeline 的 Tekton 资源。在 PAC 中,你可以在 Git 仓库中定义 PipelineRun 资源,PAC 会根据 Git 事件自动创建并管理它们。
  • Pipeline:定义可复用任务集的 Tekton 资源。你可以在 PipelineRun 中使用 pipelineRef 引用现有的 Pipeline 资源,或者使用 pipelineSpec 直接定义任务。

基本结构

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: hello
      taskSpec:
        steps:
        - name: echo
          image: alpine:latest
          script: |
            echo "Hello from PAC!"

使用现有 Pipeline

你可以引用 Kubernetes 集群中已经定义的现有 Pipeline 资源:

在哪里定义 Pipeline 资源

Pipeline 资源可以定义在以下位置:

  • 与你的 Repository CR 相同的 namespace 中
  • 作为集群范围资源(ClusterTasks)
  • 定义在你的 Git 仓库中,并使用 resolver 语法引用(请参见 Task Resolution 部分)
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:
  pipelineRef:
    name: my-pipeline-resource

事件注解

PAC 使用注解来确定何时触发 pipeline。这些注解会添加到 PipelineRun 的 metadata 中。你可以通过在 pipeline run 上使用特定注解,将不同的 Git provider 事件与各个 pipeline 匹配起来。如果有多个 pipeline run 匹配同一个事件,Pipelines as Code 会并行运行它们,并在某个 pipeline run 完成后立即将结果发布回 Git provider。

将 Pull Request 事件匹配到 Pipeline Run

你可以使用下面的示例,将一个 pipeline 与目标分支为 mainpull_request 事件匹配:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: pipeline-pr-main
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
spec:
  pipelineSpec:
    tasks:
    - name: test
      taskSpec:
        steps:
        - name: test
          image: alpine:latest
          script: |
            echo "Running tests for PR to main"

将 Push 事件匹配到 Pipeline Run

你可以使用下面的示例,将一个 pipeline 与目标分支为 refs/heads/main 的 push 事件匹配:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: pipeline-push-on-main
  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: alpine:latest
          script: |
            echo "Building on push to main"

分支规范

你可以通过添加以逗号分隔的条目来指定多个分支。例如,"[main, release-nightly]"。此外,你还可以指定以下内容:

  • 分支的完整引用,例如 "refs/heads/main"
  • 带有模式匹配的 glob,例如 "refs/heads/*"
  • 标签,例如 "refs/tags/1.*"

示例

多个分支:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main, release-nightly]"
    pipelinesascode.tekton.dev/on-event: "[push]"

使用 glob 匹配所有分支:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/*]"
    pipelinesascode.tekton.dev/on-event: "[push]"

分支模式:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/feature/*]"
    pipelinesascode.tekton.dev/on-event: "[push]"

标签:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/tags/1.*]"
    pipelinesascode.tekton.dev/on-event: "[push]"

注意on-target-branchon-event 注解采用官方文档中规定的标准格式。对于基于评论的触发,请使用 pipelinesascode.tekton.dev/on-comment 注解。

分支与路径过滤

分支过滤

使用 on-target-branch 注解按目标分支进行过滤。你可以使用 glob 模式来匹配多个分支:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/feature/*]"
    pipelinesascode.tekton.dev/on-event: "[push]"

过滤多个特定分支:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main, develop]"
    pipelinesascode.tekton.dev/on-event: "[push, pull_request]"

路径过滤

技术预览

通过注解将 PipelineRun 匹配到特定路径变更,仅属于技术预览功能。技术预览功能目前不受支持,且可能尚未功能完整。我们不建议在生产环境中使用。

要基于事件中的特定路径变更来触发 PipelineRun,请使用注解 pipelinesascode.tekton.dev/on-path-change

可以指定多个路径,并用逗号分隔。第一个匹配 PR 中变更文件的 glob 将触发 PipelineRun。如果你想匹配包含逗号的文件或路径,可以使用 , HTML 实体进行 HTML 转义。

你仍然需要使用 on-target-branchon-event 注解指定事件类型和目标分支。

:::important 路径变更注解限制

如果你使用 CEL 表达式(on-cel-expression),on-path-changeon-path-change-ignore 注解将被忽略。在使用 CEL 时,请使用带有 files.* 属性或 .pathChanged() 函数的 CEL 表达式进行基于路径的过滤。

:::

示例

metadata:
  name: pipeline-docs-and-manual
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
    pipelinesascode.tekton.dev/on-path-change: "[docs/**.md, manual/**.rst]"

pull_request 事件以 main 分支为目标,并且包含对 docs 目录(及其子目录)中以 .md 结尾的文件或 manual 目录中以 .rst 结尾的文件的变更时,此配置将匹配并触发 PipelineRun。

路径模式

  • 使用 glob 模式,而不是 regex
  • src/** - 匹配 src 目录及其子目录中的所有文件
  • *.go - 匹配仓库根目录中的所有 Go 文件
  • 多个模式使用逗号分隔:"[src/**,*.go,config/**]"

测试 glob 模式tkn pac CLI 提供了一个便捷的 globbing 命令,用于测试 glob 模式匹配:

tkn pac info globbing "[PATTERN]"

排除路径变更

你可以使用反向注解 pipelinesascode.tekton.dev/on-path-change-ignore,在指定路径发生变更时触发 PipelineRun。

你仍然需要指定事件类型和目标分支。如果使用 CEL 表达式,on-path-change-ignore 注解将被忽略。

docs 文件夹之外有变更时,这个 PipelineRun 会运行:

metadata:
  name: pipeline-not-on-docs-change
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
    pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/***]"

组合路径变更与忽略

你可以同时组合 on-path-changeon-path-change-ignore 注解:

metadata:
  name: pipeline-docs-not-generated
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
    pipelinesascode.tekton.dev/on-path-change: "[docs/***]"
    pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/generated/***]"

docs 目录中有变更,但 docs/generated 目录中没有变更时,此配置会触发 PipelineRun。

重要on-path-change-ignore 注解始终优先于 on-path-change 注解。如果某个文件同时匹配这两个模式,则不会触发 PipelineRun。

高级事件匹配

Pipelines as Code 支持使用 Common Expression Language (CEL) 进行基于过滤的高级事件匹配。

:::important CEL 与注解匹配

  • 如果你使用 on-cel-expression:PAC 将使用 CEL 表达式,并忽略 on-target-branchon-event 注解
  • 如果你不使用 on-cel-expression:PAC 将使用 on-target-branchon-event 注解进行匹配

你不能同时使用 CEL 表达式和简单注解。请根据需要选择一种方式:

  • 对于基础匹配,使用简单注解(on-target-branchon-event
  • 对于复杂过滤、否定条件和高级场景,使用 CEL 表达式

:::

与简单的 on-target-branch 注解匹配相比,CEL 表达式支持复杂过滤和否定条件。

CEL 表达式格式

使用 pipelinesascode.tekton.dev/on-cel-expression 注解和一个 CEL 表达式:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: cel-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" && target_branch == "main"
spec:
  pipelineSpec:
    tasks:
    - name: test
      taskSpec:
        steps:
        - name: test
          image: alpine:latest
          script: |
            echo "Running tests"

可用的 CEL 字段和函数

基本字段

  • event:push 或 pull_request 事件
  • target_branch:目标分支
  • source_branchpull_request 事件的源分支。对于 push 事件,它与 target_branch 相同
  • event_title:匹配事件标题,例如 push 事件的提交标题,以及 pull_request 事件的 pull request 或 merge request 标题。目前仅支持 GitHub、GitLab 和 Bitbucket Cloud
  • last_commit_title:事件中最后一次提交的标题(平台增强功能 - upstream Tekton 中不可用)

文件变更字段

这些字段允许你根据事件中的特定文件变更进行过滤:

  • files.all:所有变更文件(新增、修改、删除、重命名)
  • files.added:已新增的文件
  • files.deleted:已删除的文件
  • files.modified:已修改的文件
  • files.renamed:已重命名的文件

注意:对于 pull request,属于该 pull request 的每个文件都会被列出。这些属性同时适用于 push 和 pull_request 事件。

高级字段

  • body:来自 Git provider 的完整 payload body(技术预览)
  • headers:来自 Git provider 的 HTTP headers(以 map 形式提供,headers 始终为小写)

函数

  • .matches(pattern):将字符串与 regex pattern 进行匹配
  • .pathChanged():字符串的后缀函数。该字符串可以是一个 glob 模式,用于检查路径是否发生变化。目前仅支持 GitHub 和 GitLab 作为 provider。注意:.pathChanged() 支持 glob 模式,但不支持不同类型的变更(新增、修改、删除)。如需更精细的过滤,请使用 files.* 属性
  • .startsWith(prefix):检查字符串是否以给定前缀开头
  • .contains(substring):检查字符串是否包含给定子串
  • .exists(iterator, condition):检查集合中是否有任意元素匹配条件(与 files.* 属性一起使用)

CEL 表达式示例

匹配来自特定分支的 Pull Request

要匹配目标分支为 main 且来自 wip 分支的 pull_request 事件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      target_branch == "main" &&
      source_branch.startsWith("wip")

使用 .pathChanged() 进行基于路径的过滤

NOTE

Pipelines-as-Code 支持两种方式来匹配特定事件中变更的文件:

  • .pathChanged() 后缀函数(在 CEL 表达式中) - 支持 glob 模式,但不支持不同类型的“变更”(新增、修改、删除)
  • files.* 属性(在 CEL 表达式中) - 可以针对特定类型的变更文件,并支持使用 CEL 表达式
  • on-path-change 注解 - 更简单的基于注解的方式(技术预览)

如果你只想在某个路径发生变更时运行 pipeline,可以使用带有 glob 模式的 .pathChanged() 后缀函数:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      "docs/*.md".pathChanged()

这会匹配 docs 目录中的每个 markdown 文件。

匹配多个路径模式

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "push" &&
      ("src/**".pathChanged() || "config/**".pathChanged())

注意.pathChanged() 支持 glob 模式,但不会区分文件变更类型(新增、修改、删除、重命名)。如需更精确的过滤,请使用下文所述的 files.* 属性。

事件标题匹配

匹配所有标题以 [DOWNSTREAM] 开头的 pull request:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      event_title.startsWith("[DOWNSTREAM]")

排除分支

要在 pull_request 事件上运行 pipeline,但跳过 experimental 分支:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      !source_branch.matches("^experimental.*")

复杂 CEL 表达式示例

一个结合多个条件的完整示例:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |-
      (
        source_branch.matches("^(main|master|release-.*)$") ||
        !event_title.contains("Auto-commit")
      ) && ((
        event == "push" && (
          source_branch.matches("^(main|master|release-.*)$") ||
          target_branch.matches("^(main|master|release-.*)$") ||
          target_branch.startsWith("refs/tags/")
        )
      ) || (
        event == "pull_request" && (
          target_branch.matches("^(main|master|release-.*)$")
        )
      ))

此表达式:

  • 匹配 push 或 pull_request 事件
  • 仅在 main、master 或 release-* 分支(或标签)上触发
  • 排除标题中包含 "Auto-commit" 的提交(除非位于受保护分支上)

通过正则表达式按分支匹配 PipelineRun

使用正则表达式匹配分支名。例如,为源分支名包含子串 feat/pull_request 事件触发 PipelineRun:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      source_branch.matches(".*feat/.*")

使用 Files 属性按文件变更匹配 PipelineRun

你可以使用 files 属性来匹配特定类型的文件变更。这比 .pathChanged() 更强大,因为它可以针对特定的变更类型(新增、修改、删除、重命名)。

匹配 tmp 目录中的任意变更文件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      files.all.exists(x, x.matches('tmp/'))

匹配 srcpkg 目录中的任意新增文件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      files.added.exists(x, x.matches('src/|pkg/'))

匹配名称为 test.go 的修改文件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      files.modified.exists(x, x.matches('test.go'))

可用的文件属性

  • files.all:所有变更文件(新增、修改、删除、重命名)
  • files.added:已新增的文件
  • files.deleted:已删除的文件
  • files.modified:已修改的文件
  • files.renamed:已重命名的文件

过滤 PipelineRun 以排除非代码变更

当仅更改文档或配置文件时,排除 PipelineRun。此示例过滤 pull_request 事件,以排除仅影响文档、配置文件或其他非代码文件的变更:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      target_branch == "main" &&
      !files.all.all(x, x.matches('^docs/') || x.matches('\\.md$') || x.matches('(\\.gitignore|OWNERS|PROJECT|LICENSE)$'))

此表达式将:

  • 仅匹配目标分支为 mainpull_request 事件
  • 如果所有变更文件都匹配以下任一模式,则排除该 PipelineRun:
    • docs/ 目录中的文件(^docs/
    • Markdown 文件(\\.md$
    • 常见的仓库元数据文件(.gitignoreOWNERSPROJECTLICENSE

注意:在 CEL 表达式中使用 regex 模式时,请记得正确转义特殊字符。反斜杠(\)需要写成双反斜杠(\\),以便在 CEL 字符串上下文中正确转义。

按事件标题匹配 PipelineRun

按标题匹配 pull request 或提交。event_titlepull_request 事件中表示 pull request 标题,在 push 事件中表示提交标题:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "pull_request" &&
      event_title.startsWith("[DOWNSTREAM]")

匹配标题中不包含 "Auto-commit" 的提交:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      event == "push" &&
      !event_title.contains("Auto-commit")

基于 Body Payload 匹配 PipelineRun

技术预览

基于 body payload 匹配 PipelineRun,仅属于技术预览功能。技术预览功能目前不受支持,且可能尚未功能完整。我们不建议在生产环境中使用。

Git provider 传入的 payload body 可在 CEL 变量中以 body 访问。你可以利用它基于 Git provider 发送的任意数据进行过滤。

例如,在 GitHub 上,只有当 pull request 的目标为 main、作者为 superuser,且 action 为 synchronize(即 pull request 上发生了更新)时才匹配:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      body.pull_request.base.ref == "main" &&
      body.pull_request.user.login == "superuser" &&
      body.action == "synchronize"

重要说明

  • 当在 Pull Request 上匹配 body payload 时,像 /retest 这样的 GitOps 评论将不会按预期工作,因为此时 payload body 变成了评论的 body,而不是原始的 pull request payload
  • 如果使用基于 body payload 的 CEL 来重新测试 Pull Request,请通过 amend 并强制推送来制造一次虚拟更新:git commit --amend --no-edit && git push --force-with-lease

按请求头匹配 PipelineRun

根据 Git provider 发送的 headers 进行过滤。headers 以列表形式提供,且始终为小写。

通过检查 header 仅匹配 GitHub 的 pull_request 事件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      headers['x-github-event'] == "pull_request"

仅匹配 GitLab merge request 事件:

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-cel-expression: |
      headers['x-gitlab-event'] == "Merge Request Hook"

运行中取消

pipelinesascode.tekton.dev/cancel-in-progress 注解允许你在触发同类型的新 pipeline 时,自动取消正在运行的 pipeline。

配置取消

将该注解设置为 "true" 即可启用自动取消:

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/cancel-in-progress: "true"
spec:
  pipelineSpec:
    tasks:
    - name: hello
      taskSpec:
        steps:
        - name: echo
          image: alpine:latest
          script: |
            echo "Hello from PAC!"

行为

  • 当触发新的 pipeline 时(例如对同一分支进行新的 push),任何当前正在运行且具有相同注解的 pipeline 都会自动取消
  • 这有助于防止同一分支上同时运行多个 pipeline
  • 被取消的 pipeline 会在 Git provider 中显示为 "Cancelled" 状态

使用场景示例

防止 main 分支上的重复运行

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
    pipelinesascode.tekton.dev/cancel-in-progress: "true"

这可确保如果短时间内有多个 push 发生到 main 分支,只有最新的 pipeline 会运行,从而避免资源浪费。

与 Pull Request 一起使用

metadata:
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
    pipelinesascode.tekton.dev/cancel-in-progress: "true"

当 PR 使用新提交更新时,该 PR 的任何正在运行的 pipeline 都会被取消,并启动一个新的 pipeline。

为提交和 URL 参数化

你可以使用 {{<var>}} 格式的动态可展开变量来指定提交和 URL 的参数。这些变量可用于:

两类变量

PAC 支持两类变量:

  • PAC 动态变量{{ variable_name }}):PAC 特定变量(例如 {{ revision }}{{ repo_url }}),在创建 PipelineRun 之前由 PAC 替换
  • Tekton 参数$(params.param-name)):可在 Repository CR 的 spec.params 中定义的 Tekton Pipeline 参数(详情请参见 Advanced Repository Configuration

本节介绍 PAC 动态变量。关于 Repository CR 参数,请参见 Advanced Repository Configuration

  • PipelineRun params
  • Task 参数
  • Step 脚本和命令
  • pipeline 定义中的任何字符串值

可用变量

目前,你可以使用以下变量:

变量描述示例可用范围
{{ repo_owner }}仓库所有者myorg, username所有事件
{{ repo_name }}仓库名称my-repo所有事件
{{ repo_url }}仓库完整 URLhttps://gitlab.com/user/repo所有事件
{{ revision }}某次提交的完整 SHA revisionabc123def456...所有事件
{{ sender }}提交发送者的用户名或账户 IDusername, user123所有事件
{{ source_branch }}事件来源所在的分支名main, feature/xyz所有事件
{{ target_branch }}事件所指向的分支名。对于 push 事件,它与 source_branch 相同main, develop所有事件
{{ pull_request_number }}pull request 或 merge request 编号,仅为 pull_request 事件类型定义123仅限 Pull Request 事件
{{ git_auth_secret }}为检查私有仓库而使用 Git provider token 自动生成的 secret 名称pac-gitauth-repo-xxx所有事件(仅私有仓库)

变量使用示例

Git 仓库信息

spec:
  params:
  - name: repo-url
    value: "{{ repo_url }}"
  - name: revision
    value: "{{ revision }}"
  - name: branch
    value: "{{ source_branch }}"
  pipelineSpec:
    tasks:
    - name: clone
      taskSpec:
        steps:
        - name: clone
          image: alpine/git:latest
          script: |
            git clone {{ repo_url }}
            cd {{ repo_name }}
            git checkout {{ revision }}

事件信息

spec:
  params:
  - name: sender
    value: "{{ sender }}"
  - name: branch
    value: "{{ target_branch }}"
  pipelineSpec:
    tasks:
    - name: notify
      taskSpec:
        steps:
        - name: notify
          image: alpine:latest
          script: |
            echo "Pipeline triggered by {{ sender }} on branch {{ target_branch }}"

Pull Request 信息

spec:
  params:
  - name: pr-number
    value: "{{ pull_request_number }}"
  pipelineSpec:
    tasks:
    - name: test
      taskSpec:
        steps:
        - name: test
          image: alpine:latest
          script: |
            echo "Testing Pull Request #{{ pull_request_number }}"

注意{{ pull_request_number }} 变量仅适用于 pull_request 事件类型。对于 push 事件,此变量不会被填充。

使用 Git 认证 secret

对于私有仓库,PAC 会自动生成用于 git 认证的 secret。你可以在 pipeline 任务中引用该 secret:

spec:
  pipelineSpec:
    tasks:
    - name: clone
      taskSpec:
        steps:
        - name: clone
          image: alpine/git:latest
          env:
          - name: GIT_CREDENTIALS
            valueFrom:
              secretKeyRef:
                name: "{{ git_auth_secret }}"
                key: password
          script: |
            git clone https://github.com/user/private-repo

注意{{ git_auth_secret }} 变量仅适用于私有仓库。当你为私有仓库配置认证时,PAC 会自动创建该 secret(请参见 Configure Authentication for Private Repositories)。secret 名称格式为 pac-gitauth-<repository-name>-<hash>

Task Resolution

PAC 可以自动从多个来源解析 task。你可以使用 PAC 注解(推荐)或 Tekton resolver 语法。

使用 PAC 注解(推荐)

PAC 提供了注解,用于自动获取并嵌入来自 Tekton Hub 的远程 task。这种方式比使用 resolver 语法更简单。

远程 Task 注解

使用注解引用 Tekton Hub 中的 task:

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"
    pipelinesascode.tekton.dev/task-1: "golangci-lint"
spec:
  pipelineSpec:
    tasks:
    - name: fetch
      taskRef:
        name: git-clone
      params:
        - name: url
          value: "{{ repo_url }}"
        - name: revision
          value: "{{ revision }}"
    - name: lint
      taskRef:
        name: golangci-lint
      runAfter: [fetch]

工作方式

  • 注解 pipelinesascode.tekton.dev/task: "git-clone" 告诉 PAC 从 Tekton Hub 获取该 task
  • 使用带编号的注解(task-1task-2 等)引用更多 task
  • PAC 会自动将所有引用的 task 定义嵌入到你的 PipelineRun 中
  • 然后你可以使用 Tekton Hub 中的 task 名称,通过 taskRef.name 引用它们

注解编号

  • pipelinesascode.tekton.dev/task:第一个 task(等同于 task-0
  • pipelinesascode.tekton.dev/task-1:第二个 task
  • pipelinesascode.tekton.dev/task-2:第三个 task
  • 以此类推...

更多详情请参见 PAC Resolver

使用 Resolver 语法

你也可以使用 Tekton 的 resolver 语法来引用 task。

本地 Task

引用同一仓库中定义的 task:

.tekton/
├── pipelinerun.yaml
└── tasks/
    └── build-task.yaml
spec:
  pipelineSpec:
    tasks:
    - name: build
      taskRef:
        resolver: git
        params:
        - name: url
          value: "{{ repo_url }}"
        - name: revision
          value: "{{ revision }}"
        - name: pathInRepo
          value: .tekton/tasks/build-task.yaml

Tekton Hub Task

引用 Tekton Hub 中的 task:

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

远程 URL Task

使用 PAC 注解引用远程 URL 中的 task(推荐):

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: my-pipeline
  annotations:
    # PAC automatically handles authentication for remote tasks
    pipelinesascode.tekton.dev/task: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.9/git-clone.yaml"
spec:
  pipelineSpec:
    tasks:
    - name: build
      taskRef:
        name: git-clone  # Reference the task by name

Pipeline 示例

简单构建 Pipeline

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]"
spec:
  pipelineSpec:
    tasks:
    - name: build
      taskSpec:
        steps:
        - name: build
          image: golang:1.21
          script: |
            go build -o app ./cmd/app
            go test ./...

面向 PR 的测试 Pipeline

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: test-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[pull_request]"
spec:
  pipelineSpec:
    tasks:
    - name: test
      taskSpec:
        steps:
        - name: run-tests
          image: golang:1.21
          script: |
            go test -v ./...
            go vet ./...
            go fmt ./...

多阶段 Pipeline

此示例演示了一个完整的 CI pipeline,使用真实仓库完成 clone、test 和 build 阶段:

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: ci-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[main]"
    pipelinesascode.tekton.dev/on-event: "[push, pull_request]"
spec:
  workspaces:
  - name: source
    emptyDir: {}
  pipelineSpec:
    workspaces:
    - name: source
    tasks:
    - name: clone
      workspaces:
      - name: source
      taskSpec:
        workspaces:
        - name: source
        steps:
        - name: clone
          image: alpine/git:latest
          script: |
            git clone https://github.com/tektoncd/catalog $(workspaces.source.path)
            cd $(workspaces.source.path)
            echo "Cloned repository successfully"
            ls -la
    - name: check-content
      runAfter: [clone]
      workspaces:
      - name: source
      taskSpec:
        workspaces:
        - name: source
        steps:
        - name: check
          image: alpine:latest
          script: |
            cd $(workspaces.source.path)
            echo "Repository structure:"
            ls -la
            echo "Total files:"
            find . -type f | wc -l
    - name: validate-yaml
      runAfter: [check-content]
      workspaces:
      - name: source
      taskSpec:
        workspaces:
        - name: source
        steps:
        - name: validate
          image: alpine:latest
          script: |
            cd $(workspaces.source.path)
            echo "Checking for YAML files"
            find . -name "*.yaml" -o -name "*.yml" | head -10

条件 Pipeline

根据分支使用不同的 pipeline:

# .tekton/pipelinerun-main.yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: main-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
    pipelinesascode.tekton.dev/on-event: "[push]"
spec:
  pipelineSpec:
    tasks:
    - name: deploy
      taskSpec:
        steps:
        - name: deploy
          image: deploy-tool:latest
          script: |
            deploy.sh production
# .tekton/pipelinerun-develop.yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: develop-pipeline
  annotations:
    pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/develop]"
    pipelinesascode.tekton.dev/on-event: "[push]"
spec:
  pipelineSpec:
    tasks:
    - name: deploy
      taskSpec:
        steps:
        - name: deploy
          image: deploy-tool:latest
          script: |
            deploy.sh staging

最佳实践

1. 版本控制

  • 将所有 pipeline 定义保存在 Git 中
  • 通过 Merge Requests 审查 pipeline 变更
  • 为 pipeline 版本打标签,以便实现可复现性

2. 组织方式

  • 使用具有描述性的 pipeline 名称
  • 将相关任务分组放在一起
  • 针对不同类型的 pipeline 使用独立文件

3. 安全性

  • 不要在 pipeline 文件中硬编码 secrets
  • 对敏感数据使用 Kubernetes Secrets
  • 使用 RBAC 限制 pipeline 权限

4. 可复用性

  • 创建可复用的 task 定义
  • 尽可能使用 Tekton Hub task
  • 在多个仓库之间共享通用 task

5. 测试

  • 在 feature 分支中测试 pipeline 变更
  • 使用 Merge Request pipeline 验证变更
  • 保持 pipeline 简洁且易于维护

故障排查

Pipeline 未触发

  1. 检查注解是否正确:

    cat .tekton/pipelinerun.yaml | grep pipelinesascode.tekton.dev
  2. 验证分支名称是否匹配:

    git branch --show-current
  3. 检查 PAC 控制器日志:

    kubectl logs -n <pac-namespace> -l app=pipelines-as-code-controller --tail=100  # Replace <pac-namespace> with your actual namespace (default: tekton-pipelines)

变量未解析

  1. 验证变量语法:使用 {{ variable_name }} 格式,例如 {{ revision }}{{ repo_url }}
  2. 检查变量名拼写:确保变量名完全一致(例如 {{ repo_owner }}{{ source_branch }}
  3. 验证变量可用性:某些变量(如 {{ pull_request_number }})仅适用于 pull_request 事件
  4. 查看 PAC 控制器日志中的变量解析错误

找不到 Task

  1. 验证 task 引用是否正确
  2. 检查仓库中是否存在 task 文件
  3. 验证 Tekton Hub task 名称
  4. 检查远程 task 的网络连通性

下一步