Help us learn about your current experience with the documentation. Take the survey.

CI/CD 组件示例

  • 版本:Free, Premium, Ultimate
  • 提供:GitLab.com, GitLab Self-Managed, GitLab Dedicated

测试组件

根据组件的功能,测试组件 可能需要在仓库中添加额外的文件。 例如,用于在特定编程语言中进行代码检查、构建和测试的组件,需要实际的源代码示例。 你可以在同一个仓库中包含源代码示例、配置文件等。

例如,Code Quality CI/CD 组件有多个测试用的代码示例

示例:测试 Rust 语言的 CI/CD 组件

根据组件的功能,测试组件 可能需要在仓库中添加额外的文件。

以下 Rust 编程语言的 “hello world” 示例为简化起见使用了 cargo 工具链:

  1. 进入 CI/CD 组件根目录。

  2. 使用 cargo init 命令初始化一个新的 Rust 项目。

    cargo init

    该命令会创建所有必需的项目文件,包括一个 src/main.rs “hello world” 示例。 此步骤足以在组件作业中使用 cargo build 构建 Rust 源代码。

    tree
    .
    ├── Cargo.toml
    ├── LICENSE.md
    ├── README.md
    ├── src
    │   └── main.rs
    └── templates
        └── build.yml
  3. 确保组件有一个用于构建 Rust 源代码的作业,例如在 templates/build.yml 中:

    spec:
      inputs:
        stage:
          default: build
          description: '定义构建阶段'
        rust_version:
          default: latest
          description: '指定 Rust 版本,使用 https://hub.docker.com/_/rust/tags 中的值,默认为 latest'
    ---
    
    "build-$[[ inputs.rust_version ]]":
      stage: $[[ inputs.stage ]]
      image: rust:$[[ inputs.rust_version ]]
      script:
        - cargo build --verbose

    在此示例中:

    • stagerust_version 输入可以从其默认值修改。 CI/CD 作业以 build- 前缀开始,并根据 rust_version 输入动态创建名称。 cargo build --verbose 命令编译 Rust 源代码。
  4. 在项目的 .gitlab-ci.yml 配置文件中测试组件的 build 模板:

    include:
      # 包含位于当前项目当前 SHA 的组件
      - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
        inputs:
          stage: build
    
    stages: [build, test, release]
  5. 为了运行测试等操作,向 Rust 代码中添加额外的函数和测试, 并在 templates/test.yml 中添加一个运行 cargo test 的组件模板和作业。

    spec:
      inputs:
        stage:
          default: test
          description: '定义测试阶段'
        rust_version:
          default: latest
          description: '指定 Rust 版本,使用 https://hub.docker.com/_/rust/tags 中的值,默认为 latest'
    ---
    
    "test-$[[ inputs.rust_version ]]":
      stage: $[[ inputs.stage ]]
      image: rust:$[[ inputs.rust_version ]]
      script:
        - cargo test --verbose
  6. 通过包含 test 组件模板来在管道中测试额外的作业:

    include:
      # 包含位于当前项目当前 SHA 的组件
      - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
        inputs:
          stage: build
      - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/test@$CI_COMMIT_SHA
        inputs:
          stage: test
    
    stages: [build, test, release]

CI/CD 组件模式

本节提供了在 CI/CD 组件中实现常见模式的实用示例。

使用布尔输入条件性配置作业

你可以通过组合 boolean 类型的输入和 extends 功能来创建带有两个条件的工作。

例如,使用 boolean 输入来配置复杂的缓存行为:

spec:
  inputs:
    enable_special_caching:
      description: '如果设置为 `true`,则配置复杂的缓存行为'
      type: boolean
---

.my-component:enable_special_caching:false:
  extends: null

.my-component:enable_special_caching:true:
  cache:
    policy: pull-push
    key: $CI_COMMIT_SHA
    paths: [...]

my-job:
  extends: '.my-component:enable_special_caching:$[[ inputs.enable_special_caching ]]'
  script: ... # 运行一些高级工具

这种模式通过将 enable_special_caching 输入传递到作业的 extends 关键字来工作。 根据 enable_special_cachingtrue 还是 false,会从预定义的隐藏作业 (.my-component:enable_special_caching:true.my-component:enable_special_caching:false) 中选择适当的配置。

使用 options 条件性配置作业

你可以创建带有多个选项的作业,实现类似 ifelseif 条件的行为。 使用 extends 结合 string 类型和多个 options 来实现任意数量的条件。

例如,使用 3 个不同的选项来配置复杂的缓存行为:

spec:
  inputs:
    cache_mode:
      description: 定义此组件使用的缓存模式
      type: string
      options:
        - default
        - aggressive
        - relaxed
---

.my-component:cache_mode:default:
  extends: null

.my-component:cache_mode:aggressive:
  cache:
    policy: push
    key: $CI_COMMIT_SHA
    paths: ['*/**']

.my-component:cache_mode:relaxed:
  cache:
    policy: pull-push
    key: $CI_COMMIT_BRANCH
    paths: ['bin/*']

my-job:
  extends: '.my-component:cache_mode:$[[ inputs.cache_mode ]]'
  script: ... # 运行一些高级工具

在此示例中,cache_mode 输入提供了 defaultaggressiverelaxed 选项, 每个选项对应一个不同的隐藏作业。 通过使用 extends: '.my-component:cache_mode:$[[ inputs.cache_mode ]]' 扩展组件作业, 作业会根据所选选项动态继承正确的缓存配置。

CI/CD 组件迁移示例

本节展示了将 CI/CD 模板和管道配置迁移为可重用 CI/CD 组件的实用示例。

CI/CD 组件迁移示例:Go

软件开发生命周期的完整管道可以由多个作业和阶段组成。 编程语言的 CI/CD 模板可能在单个模板文件中提供多个作业。 作为实践,以下 Go CI/CD 模板应该被迁移。

default:
  image: golang:latest

stages:
  - test
  - build
  - deploy

format:
  stage: test
  script:
    - go fmt $(go list ./... | grep -v /vendor/)
    - go vet $(go list ./... | grep -v /vendor/)
    - go test -race $(go list ./... | grep -v /vendor/)

compile:
  stage: build
  script:
    - mkdir -p mybinaries
    - go build -o mybinaries ./...
  artifacts:
    paths:
      - mybinaries

对于更渐进的方法,一次迁移一个作业。 从 build 作业开始,然后重复 formattest 作业的步骤。

CI/CD 模板迁移涉及以下步骤:

  1. 分析 CI/CD 作业和依赖关系,并定义迁移操作:

    • image 配置是全局的,需要移到作业定义中
    • format 作业在一个作业中运行多个 go 命令。go test 命令应该移到单独的作业中以提高管道效率。
    • compile 作业运行 go build,应该重命名为 build
  2. 定义优化策略以提高管道效率。

    • stage 作业属性应该是可配置的,以允许不同的 CI/CD 管道使用者。
    • image 键使用硬编码的镜像标签 latest。添加 golang_version 作为输入, 默认值为 latest,以实现更灵活和可重用的管道。该输入必须匹配 Docker Hub 镜像标签值。
    • compile 作业将二进制文件构建到硬编码的目标目录 mybinaries, 可以通过动态 input 和默认值 mybinaries 来增强。
  3. 为新组件创建模板 目录结构, 基于每个作业一个模板。

    • 模板名称应遵循 go 命令,例如 format.ymlbuild.ymltest.yml
    • 创建新项目,初始化 Git 仓库,添加/提交所有更改,设置远程源并推送。 修改你的 CI/CD 组件项目路径的 URL。
    • 按照 编写组件 的指导创建其他文件: README.mdLICENSE.md.gitlab-ci.yml.gitignore。以下 shell 命令 初始化 Go 组件结构:
    git init
    
    mkdir templates
    touch templates/{format,build,test}.yml
    
    touch README.md LICENSE.md .gitlab-ci.yml .gitignore
    
    git add -A
    git commit -avm "Initial component structure"
    
    git remote add origin https://gitlab.example.com/components/golang.git
    
    git push
  4. 将 CI/CD 作业创建为模板。从 build 作业开始。

    • spec 部分定义以下输入:stagegolang_versionbinary_directory

    • 添加动态作业名称定义,访问 inputs.golang_version

    • 使用类似的模式来动态设置 Go 镜像版本,访问 inputs.golang_version

    • 将阶段分配给 inputs.stage 值。

    • inputs.binary_directory 创建二进制目录,并将其作为参数添加到 go build

    • 将 artifacts 路径定义为 inputs.binary_directory

      spec:
        inputs:
          stage:
            default: 'build'
            description: '定义构建阶段'
          golang_version:
            default: 'latest'
            description: 'Go 镜像版本标签'
          binary_directory:
            default: 'mybinaries'
            description: '创建的二进制文件输出目录'
      ---
      
      "build-$[[ inputs.golang_version ]]":
        image: golang:$[[ inputs.golang_version ]]
        stage: $[[ inputs.stage ]]
        script:
          - mkdir -p $[[ inputs.binary_directory ]]
          - go build -o $[[ inputs.binary_directory ]] ./...
        artifacts:
          paths:
            - $[[ inputs.binary_directory ]]
    • format 作业模板遵循相同的模式,但只需要 stagegolang_version 输入。

      spec:
        inputs:
          stage:
            default: 'format'
            description: '定义格式化阶段'
          golang_version:
            default: 'latest'
            description: 'Golang 镜像版本标签'
      ---
      
      "format-$[[ inputs.golang_version ]]":
        image: golang:$[[ inputs.golang_version ]]
        stage: $[[ inputs.stage ]]
        script:
          - go fmt $(go list ./... | grep -v /vendor/)
          - go vet $(go list ./... | grep -v /vendor/)
    • test 作业模板遵循相同的模式,但只需要 stagegolang_version 输入。

      spec:
        inputs:
          stage:
            default: 'test'
            description: '定义测试阶段'
          golang_version:
            default: 'latest'
            description: 'Golang 镜像版本标签'
      ---
      
      "test-$[[ inputs.golang_version ]]":
        image: golang:$[[ inputs.golang_version ]]
        stage: $[[ inputs.stage ]]
        script:
          - go test -race $(go list ./... | grep -v /vendor/)
  5. 为了测试组件,修改 .gitlab-ci.yml 配置文件, 并添加 tests

    • build 作业指定不同的 golang_version 值作为输入。

    • 修改你的 CI/CD 组件路径的 URL。

      stages: [format, build, test]
      
      include:
        - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/format@$CI_COMMIT_SHA
        - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
        - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
          inputs:
            golang_version: "1.21"
        - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/test@$CI_COMMIT_SHA
          inputs:
            golang_version: latest
  6. 添加 Go 源代码来测试 CI/CD 组件。go 命令期望在根目录中有 go.modmain.go 的 Go 项目。

    • 初始化 Go 模块。修改你的 CI/CD 组件路径的 URL。

      go mod init example.gitlab.com/components/golang
    • 创建一个包含主函数的 main.go 文件,例如打印 Hello, CI/CD component。 你可以使用代码注释通过 GitLab Duo Code Suggestions 生成 Go 代码。

      // 指定包,导入所需的包
      // 创建主函数
      // 在主函数内打印 "Hello, CI/CD Component"
      
      package main
      
      import "fmt"
      
      func main() {
        fmt.Println("Hello, CI/CD Component")
      }
    • 目录树应如下所示:

      tree
      .
      ├── LICENSE.md
      ├── README.md
      ├── go.mod
      ├── main.go
      └── templates
          ├── build.yml
          ├── format.yml
          └── test.yml

按照 将 CI/CD 模板转换为组件 部分中的其余步骤来完成迁移:

  1. 提交并推送更改,验证 CI/CD 管道结果。
  2. 按照 编写组件 的指导更新 README.mdLICENSE.md 文件。
  3. 发布组件 并在 CI/CD 目录中验证它。
  4. 将 CI/CD 组件添加到你的暂存/生产环境中。

GitLab 维护的 Go 组件 提供了从 Go CI/CD 模板成功迁移的示例, 并增强了输入和组件最佳实践。你可以检查 Git 历史记录以了解更多信息。