3、.gitlab-ci.yml基础:YAML语法入门,Job、Stage、Script基本概念,第一个Pipeline的编写与运行

好,咱们正式开始动手了。

上一章我们聊了为什么嵌入式开发需要CI/CD,这一章直接进入实操。你想想看,GitLab CI的核心就藏在一个文件里——.gitlab-ci.yml。说白了,你把这个文件往仓库根目录一放,GitLab就会自动识别并开始干活。

我个人习惯,每次新建项目第一件事就是创建这个文件。哪怕里面只写一个简单的Job,也能让团队看到CI已经就绪。嗯,咱们先从YAML语法说起。

YAML语法,没那么可怕

YAML的宗旨就是「人类可读」。它用缩进来表示层级关系,用冒号分隔键值对。我见过不少工程师一看到缩进就头疼,其实记住两条规则就够了:

  • 缩进必须一致:用空格,别用Tab。我建议你统一用2个空格。
  • 冒号后面要有空格key: value,冒号后面必须跟一个空格。

来看一个最简单的例子:

# 这是一个注释
my_job:
  script:
    - echo "Hello, Embedded World!"

这段代码定义了一个Job,名字叫my_job。它只做一件事:打印一句话。注意看缩进,script前面有两个空格,- echo前面有四个空格。层级关系一目了然。

小技巧: 我刚开始写YAML时经常犯缩进错误。后来发现一个办法——在VS Code里安装YAML插件,它会自动帮你检查缩进。另外,GitLab CI的Lint工具也能在线验证语法,省心不少。

Job、Stage、Script,三个核心概念

这三个概念是Pipeline的基石。咱们一个一个说。

Job(任务)

Job是Pipeline的最小执行单元。每个Job都包含一个script,告诉GitLab要执行什么命令。你可以定义任意多个Job,它们可以并行运行,也可以按顺序运行。

我在项目中遇到过一种情况:有人把编译和测试写在了同一个Job里。结果测试失败了,还得重新编译一遍,浪费时间。记住,一个Job只做一件事,这是最佳实践。

Stage(阶段)

Stage是Job的逻辑分组。它定义了Job的执行顺序。常见的Stage有:buildtestdeploy。同一个Stage里的Job会并行执行,不同Stage之间按顺序执行。

举个例子:

stages:
  - build
  - test
  - deploy

这个配置告诉GitLab:先跑build阶段的Job,全部通过后再跑test阶段,最后才是deploy。为什么会这样设计?因为编译不通过,测试就没意义;测试不通过,部署就是灾难。

Script(脚本)

Script就是你要执行的命令。可以是Shell命令,也可以是调用Makefile、CMake等构建工具。对于嵌入式开发,最常见的script就是:

script:
  - make clean
  - make all

嗯,这里要注意:Script里的命令默认在项目根目录执行。如果你的嵌入式项目有子目录,记得先cd进去。

核心总结:
  • Job = 一个具体任务(比如编译固件)
  • Stage = 任务的分组和顺序(先编译,再测试)
  • Script = 任务的具体命令(make、cmake、gcc等)

第一个Pipeline,动手写起来

光说不练假把式。咱们写一个完整的.gitlab-ci.yml,适用于嵌入式C项目。

stages:
  - build
  - test

build_firmware:
  stage: build
  script:
    - mkdir -p build
    - cd build
    - cmake ..
    - make
  artifacts:
    paths:
      - build/firmware.hex

run_unit_tests:
  stage: test
  script:
    - cd build
    - ctest --output-on-failure
  dependencies:
    - build_firmware

这个Pipeline做了两件事:

  1. build_firmware:创建build目录,运行CMake和Make,生成固件文件。注意我用了artifacts,它会把生成的firmware.hex保存下来,供后续Job使用或下载。
  2. run_unit_tests:依赖build阶段的产物,运行单元测试。这里用了dependencies,确保测试Job能拿到编译好的文件。

我曾经犯过一个错误:忘记在test阶段加上dependencies,结果测试Job找不到编译产物,直接报错。嗯,从那以后我每次写Pipeline都会检查依赖关系。

避坑指南: 嵌入式项目经常需要交叉编译工具链。如果你在Runner上没装对应的工具链,Pipeline会失败。我建议在Runner的镜像里预装好工具链,或者在before_script里安装。千万别在script里临时下载,那会慢得让你怀疑人生。

如何运行和查看Pipeline

文件写好了,怎么跑起来?很简单:

  1. .gitlab-ci.yml提交到仓库根目录
  2. 推送到GitLab远程仓库
  3. 打开GitLab项目页面,点击左侧的「CI/CD」→「Pipelines」

你会看到Pipeline正在运行。每个Job都有实时日志输出,哪里出错一目了然。我个人习惯在开发阶段把Pipeline触发方式设为「手动触发」,等调试稳定了再改成「自动触发」。

对了,还有一个实用功能:Pipeline的图形化视图。GitLab会把Stage和Job画成流程图,绿色表示通过,红色表示失败。你想想看,团队Review代码时,看到一片绿色,心里多踏实。

小结

这一章我们搞定了三件事:YAML语法基础、Job/Stage/Script的概念、第一个Pipeline的编写。说白了,.gitlab-ci.yml就是一份「自动化工作说明书」,你告诉GitLab做什么、按什么顺序做,剩下的交给它。

下一章,我们会深入嵌入式场景,聊聊如何配置交叉编译环境、如何管理固件产物。到时候你会发现,CI/CD在嵌入式开发中能做的事情,远比你想的要多。