Skip to main content

GitLab CI/CD with Flutter

· 约18分钟

目标:学习 CI/CD 的基本概念,GitLab CI/CD 使用方法。

前提:有 GitLab 的账号和基础知识,了解远程仓库、分支、提交、推送、合并申请等概念。如果不了解,可以学习教程 Hello World in GitLab

内容:学习 CI/CD 的基本概念,创建并部署一个 Flutter 项目到 GitLab,使用GitLab CI/CD 自动化执行项目的测试、打包、分发。

演示平台:macOS

CI/CD 的基本概念

CI (Continuous Integration)持续集成。集成是指将代码集成到主干。

CD (Continuous Delivery,Continuous Deployment)持续交付,持续部署。交付是指将软件的某一版本交付给质量团队或用户,以供评审。部署是指软件通过评审后,进入生产阶段,部署到生产环境。

“持续”强调应用开发是一个长期的不断迭代的过程,集成、交付、部署这三个动作会不断发生。

CI/CD 是一种方法,通过在应用开发阶段引入自动化来频繁向客户交付应用。其核心概念是持续集成、持续交付和持续部署。

GitLab CI/CD 是一个内置在 GitLab 中的工具,用于通过 CI/CD 方法进行软件开发。

集成、交付、部署是一个连贯的流程。当我们在谈论 CI/CD 时,有可能仅指持续集成和持续交付,也可能指持续集成、持续交付和持续部署三者。我们没必要纠结于此,只需要记住 CI/CD 表现为一个流程(通常形象地表述为 pipeline,即管道)。

工作流程

在学习使用 GitLab CI/CD之前,我们先看看如果没有 GitLab CI/CD ,在 GitLab 的工作可能会如何进行?

以 Flutter 项目为例子来说明工作流程(步骤1需要跟做,其余步骤仅展示工作流程):

  1. 创建一个包含测试的 Flutter 项目并部署到 GitLab 仓库。

    创建 Flutter 项目可参考教程 创建您的第一个Flutter应用

    在 GitLab 网站创建一个名为 myFlutter 的新项目:

    create-project-01

    我们要把已存在的项目推送到 GitLab 的 myFlutter 项目,参考 Push an existing folder 的提示命令行:

    create-project-02

    //进入 Flutter 项目位置
    cd ~/workspace/my_flutter

    //初始化,把当前目录变为 Git 可以管理的仓库
    git init

    //指定远程 URL,Push an existing folder 命令行展示了 URL。
    git remote add origin git@team.xxx.net.cn:Josie/myflutter.git

    //添加文件,提交文件
    git add .
    git commit -m 'Initial commit'

    //推送本地项目到远程
    git push -u origin master

    Flutter 项目原本有 README.md 文件,不需再次创建。

  1. 团队多人协作开发,每个人有自己的分支。开发人员提交代码,提交前运行测试(在终端运行命令):

    flutter test
  2. 分支开发完成后,提出合并申请并处理矛盾冲突,合并前再次运行测试(在终端运行命令),如果测试通过就合并到主分支:

    flutter test
  3. 完成某一版本的开发后,把 Flutter 项目构建为 APK(在终端运行命令):

    flutter build apk
  4. 把 APK 分发到 AppCenter(在终端运行命令):

    appcenter login
    appcenter distribute release -f [APK_FILE_PATH] -g [GROUP] --app [USER_NAME]/[PROJECT]
  5. AppCenter 向测试人员交付应用,或将应用发布到应用商店。

在这个过程中,步骤3是“集成”,步骤4、5、6是“交付”“部署”。这是一个简化的开发过程。在真实开发过程中,这几个步骤会不断重复发生,并且更复杂。

GitLab CI/CD

GitLab CI/CD 可以自动执行部分操作(比如步骤3、4、5),将其流程化、规范化,减少人工操作可能带来的问题。

GitLab CI/CD 自动执行工作流程,需要两样东西:定义任务的文件,按照这份文件执行任务的程序。其中,定义任务的文件名为 .gitlab-ci.yml,执行任务的程序是 GitLab Runner。

下面,我们先配置 GitLab Runner。

GitLab Runner

GitLab Runner 是一个允许计算机执行任务并将结果反馈给 GitLab 的程序,即 GitLab Runner 可以自动执行文件定义的任务。当一个新的提交被推送到 GitLab 或提交合并申请时,会触发 runner 执行新任务,运行特定作业,并在 GitLab 展示执行结果。

在 GitLab 的 Flutter 项目中,跳转到 Setting > CI/CD > Runners(点击 Expand) > Specific Runners

gitlab-runner-setting-01

Specific runners 点击按钮 Show Runner installation instructions。注意,注册 gitlab-runner 会用到这里提及的 GitLab 实例 URLregistration token 注册令牌

gitlab-runner-setting-02

选择当前设备环境,例如 macOS。下面提示相应的下载安装命令,按照提示在终端进行操作。

gitlab-runner-setting-03

让我们来看看下载安装命令的具体意义:

  • 下载二进制文件:

    sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64s
  • 赋予可执行权限给二进制文件:

    sudo chmod +x /usr/local/bin/gitlab-runner
  • 运行刚才下载的文件,注册 gitlab-runner:

    sudo gitlab-runner register --url $GITLAB_INSTANCE_URL --registration-token $REGISTRATION_TOKEN

    //如果以上命令报错,请使用下面的命令
    sudo gitlab-runner register

    GITLAB_INSTANCE_URL 是 GitLab 实例 URL。
    REGISTRATION_TOKEN 是注册令牌。

    其中,注册 gitlab-runner 时,需要进行一些设置:

    Enter the GitLab instance URL(for example, http://gitlab.com/):
    #(输入GitLab 实例 URL,按回车输入参数值)

    Enter the registration token:
    #(输入注册令牌,按回车输入参数值)

    Enter a description for the runner:
    #(输入runner的描述,直接按回车则输入[]内的默认值)
    A shell runner for my flutter project.

    Enter tags for the runner (comma-separated):
    #(输入 runner 标签,可以有多个,用逗号隔开。标签用于识别 runner)
    flutter

    Enter an executor: custom, docker-ssh, shell, ssh, virtualbox, docker, parallels, docker+machine, docker-ssh+machine, kubernetes:
    #(选择执行器。我们将使用shell,输入 shell 并按回车)
    shell

Runner 的 description 描述、token 标签可以再次修改。
一个项目可以有多个 runner,只需要再次执行注册命令 sudo gitlab-runner register,就能创建其他 runner。

切换到主目录,安装 gitlab-runner,启动 gitlab-runner:

cd ~
gitlab-runner install
gitlab-runner start

运行 gitlab-runner:

gitlab-runner run

如果出现以下提示:

WARNING: Running in user-mode.                     
WARNING: Use sudo for system-mode:
WARNING: $ sudo gitlab-runner...

请使用下面的命令:

sudo gitlab-runner run

运行 gitlab-runner run 命令后,回到 GitLab 的 Setting > CI/CD > Runners(点击 Expand ) > Specific Runners,验证 GitLab Runner 是否正常运行,如果显示绿色圆形图标,表示已经成功安装并运行 GitLab Runner 实例。

gitlab-runner-setting-04

输入以下命令,获取帮助:

gitlab-runner help

下面,我们创建定义任务的文件 .gitlab-ci.yml

设置 CI 管道

在项目的根目录创建一个新的 GitLab 配置文件 .gitlab-ci.yml,我们可以其中定义测试、构建、分发等操作。

ci-setting-01

job 作业是 GitLab CI/CD 最小独立运行单位,定义做什么。

stages 阶段,定义何时运行 job。一个阶段可以包含多个 job。

pipeline 管道,一个 pipeline 可以包含多个 stage 和 job。每一次 commit 或 mr(merge request) 触发执行一个 pipeline 构建任务。

为什么把执行任务的过程称为 pipeline 管道?因为执行任务的过程具有以下特点:

  • 一个 pipeline 可以有多个 stage,stage 从上到下执行,只有当前 stage 执行完毕才能执行下一个 stage,否则报错。
  • 一个 stage 有多个 job,其中一个 job 执行失败,stage 算是执行失败。相同 stage 中的 job 是并行执行的。

创建单元测试管道

创建文件后,可以在 myFlutter > CI/CD > Editor > Write pipeline configuration 编辑文件,点击 Commit changes 保存提交。

ci-setting-02

我们将会在文件 .gitlab-ci.yml 输入以下内容,使得 GitLab 在适当的时机自动执行 flutter test 脚本来执行单元测试。

stages:
- test # All jobs related for testing such as Unit Test

flutter_test: # Name of the lane
stage: test # type of stage
script:
- flutter test # Run Flutter test
tags:
- flutter # Tags for runner
  • stages 属性定义阶段及其顺序。上文定义了一个名为 test 的阶段。
  • 上文定义了名为 flutter_test 作业。
  • 作业的 stage 属性定义作业属于某哪个阶段。上文定义 flutter_test 作业属于 test 阶段。
  • 作业的 script 属性定义做什么。上文定义了脚本 flutter test 执行单元测试。
  • 作业的 tags 属性定义哪个 runner 执行作业。上文指定了带有 tag flutter 的 runner。

定义文件 .gitlab-ci.yml 后,如果触发 pipeline 构建任务,将会执行 test 阶段中的作业 flutter_test,由指定 runner 执行作业中的脚本 flutter test

myFlutter > CI/CD > Editor > Visualize 以图像展示文件 .gitlab-ci.yml 的内容:有一个 test 阶段,test 阶段下有一个作业 flutter_test。

ci-setting-03

myFlutter > CI/CD > Editor > Lint 检查语法是否正确,并以表格形式展示文件 .gitlab-ci.yml 的内容。下图提示 "Status: Syntax is correct" 语法正确。

ci-setting-04

点击 Commit changes 提交文件 .gitlab-ci.yml 到远程仓库后,在 myFlutter > CI/CD > Pipelines 可以看到这次提交触发执行一个 pipeline 构建任务。

running 表示正在执行。

ci-setting-05

passed 表示结束并且执行成功。

ci-setting-06

点击 passed 查看细节。一个 Test 阶段中有一个名为 flutter_test 的作业。点击 flutter_test 查看细节。

ci-setting-07

可以看到,runner 执行了命令 flutter test,并提示 All tests passed! 所有测试通过。

ci-setting-08

定义构建工作

在 test 阶段下面,添加 build 阶段:

stages:
- test # All jobs related for testing such as Unit Test
- build # All jobs related for building app for Android
  • 按顺序定义,先执行 test 阶段的作业,再执行 build 阶段的作业。

在 flutter_test 下面定义 flutter_build_android 作业:

####
#### flutter_test lane
####
flutter_build_android: #Job name
stage: build # kind of job
before_script:
- flutter packages get
- flutter clean
script:
- flutter build apk
artifacts:
paths:
- build/app/outputs/apk/release/app-release.apk
tags:
- flutter
  • flutter_build_android 作业,该作业用于构建 Android 应用程序。
  • before_script 是在作业的 script 之前执行的命令行。flutter packages get 下载依赖项, flutter clean 清除缓存。
  • flutter build apk 构建可安装在Android设备上的 APK。

此时的 .gitlab-ci.yml 管道看起来应该如下图:

ci-setting-09

提交文件 .gitlab-ci.yml 到远程仓库后, GitLab CI/CD 将会自动构建 APK,点击 flutter_build_apk 查看细节。

ci-setting-10

ci-setting-11

设置 CD 管道

AppCenter 可以将应用发布到应用商店,生成应用发布,运行单元测试和设备上的测试,向测试人员交付应用,收集分析和诊断数据。

设置 CD 管道把应用程序分发到 AppCenter,我们先安装配置 AppCenter。本地安装AppCenter,可以使用命令行安装:

npm install -g appcenter-cli

yarn add appcenter-cli

运行命令行,输出帮助说明,证明安装成功:

appcenter help

打开 App Center 网页,注册并登录。创建新的应用 Add new > Add new app,填写应用名称 App name 为 myFlutter,选择操作系统OS为 Android,选择平台 Platform 为 Java/Kotlin。

cd-setting-01

cd-setting-02

转到此页面生成api token。填写描述GitLabToken,选择Full Access,确认生成api token。请复制并保存api token到安全的位置,因api token只会出现一次,无法再次查看。

cd-setting-03

返回GitLab菜单栏 > Setting > CI/CD > Variables。把刚才保存的api token设置为环境变量 APPCENTER_API_TOKEN。api token将用于在 App Center 中进行身份验证。

cd-setting-04

编辑文件.gitlab-ci.yml。在 App Center 项目中指定正确的 [username][project] 的值。
这两个值可以在项目浏览器的 URL 中找到:

cd-setting-08

在 build 阶段下面,添加 deploy 阶段:

stages:
- test # All jobs related for testing such as Unit Test
- build # All jobs related for building app for Android
- deploy

在 flutter_build_android 下面定义 deploy_android 作业:

####
#### Unit test and flutter build android
####
deploy_android:
stage: deploy
dependencies:
- flutter_build_android
script:
- appcenter login --token $APPCENTER_API_TOKEN
- appcenter distribute release -f build/app/outputs/apk/release/app-release.apk -g Collaborators —app [username]/[project]
tags:
- flutter
  • deploy_android 作业,将 Android 应用程序部署到 App Center。
  • dependencies 关键词声明作业 deploy_android 依赖于之前声明的作业 flutter_build_android,这使我们能够重用之前的作业生成的文件。
  • appcenter login --token ... 使用储存在环境变量 $APPCENTER_API_TOKEN 的 api token,在 App Center 中验证身份。
  • appcenter distribute release ... 分发 APK 到 App Center 。注意,把 [username] 替换为 App Center 的 username,把[project]替换为App Center 的 App 名称,比如刚才创建的 myFlutter

最后,我们提交并将更新的 .gitlab-ci.yml 配置推送到存储库。您会看到分发到 App Center 的 APK。

cd-setting-06

cd-setting-06

cd-setting-07

至此,我们成功使用 GitLab CI/CD 工具来完成自动单元测试和分发的操作,以后再也不需要手动启动单元测试和分发应用到 AppCenter 了。

CI/CD 的优点

我们选择现在再介绍 CI/CD 的优点,相信您此时更能理解 CI/CD 的优点所在:

  • 持续集成:产品快速迭代。
  • 持续交付:不管怎么更新,软件随时可以交付。
  • 持续部署:代码在任何时刻都是可部署的,随时产生一个可部署版本,可以进入生产阶段。
  • 帮助开发人员专注于开发工作。
  • 减少人工干预,减少引入错误的机会。
  • 避免集成地狱。

卸载runner

最后,补充卸载 卸载 runner 的方法。

选择 GitLab > Settings > CI/CD > Runners(Expand) > Remove runner,移除 runner。

gitlab-runner-setting-04

在终端输入以下命令,验证 runner 是否可以链接。

$ gitlab-runner verify --delete

输出以下信息,提示 runner 状态。

Verifying runner... is alive                        runner=axS4ek5r
Verifying runner... is alive runner=VZxX4w71
ERROR: Verifying runner... is removed runner=6uth4izn
Verifying runner... is alive runner=L2poG_qD

注意,直接删除项目,runner 不会移除。

也可以用命令行移除 runner:

$ gitlab-runner verify --delete --name xxx
$ gitlab-runner verify --url xxx
$ gitlab-runner verify --token xxx
  • name 是指注册时填写的 description

注销所有 runner。

$ gitlab-runner unregister --all-runners