使用Composer创建公共类库
概述
如果多个项目中存在使用相同类库、模块的情况,此时可以考虑将类库或者模块单独抽取出来,形成独立类库,通过composer
来进行依赖管理,这样可以更方便维护,大大提升开发效率。
优势
- 可以对特定模块进行统一维护和升级
- 特定的类库可由专人进行维护,保证稳定性和可靠性
- 避免了重复开发的情况
步骤
本地开发
为了方便调试,可先在本地现有项目中开发类库,等到开发完成后,再将相关代码单独抽取出来。
- 首先在项目中创建一个存放类库的目录,如
packages/zacksleo/my-libs
,
其中packages
是类库总目录, zacksleo
是用户名,相当于命名空间的第一级,my-libs
是类库存放目录。
- 在目录中创建
composer.json
文件,并添加形如以下的内容:
1 | { |
其中,name
是类库名称,descrption
是详细说明,type
是类别,license
是使用的协议,authers
是作者信息,
minimum-stability
用来声明最小依赖,通常有dev
和 stable
可选,autoload
中的psr-4
声明了
命名空间和对应的目录,注意命名空间就当使用双反斜杠,目录使用相对路径,此外声明了目录为src`
目录
在
src
目录中添加相关代码,其中的类使用命名空间zacksleo\\my\\libs
在项目的
composer.json
中,通过path
方式引入本地类库,如可在repositories
中添加如下信息:
1 | "repositories": { |
其中my-libs
是别名,可任意填写,type
设置成path
, url
为类库所在的相对路径(与composer.json文件相对)
- 通过
composer require
命令或者在composer.json
中的require
部分添加声音,来实现依赖加载,如
composer require zacksleo/my-libs
在Github上创建库并上传代码
当在本地开发完成后,可将类库独立抽取出来(此处的my-libs
目录下的内容),并提交到Github上新建的仓库中
配置packagist并发布
- 先在packagist.org中注册好账号,以便发布包。
- 在Github的仓库中,点击
settings
,找到Intergrations & services
, 点击Add servies
, 选择Packagist
,
填写在packagist.org注册的用户名和Token(在Profile中找到Your API Token)
点击确定添加,这样,每次Github的变动,都会自动更新到packagist上,免去了手动更新的麻烦
本地依赖改成线上版本, 并清除开发代码
类库一经发布到packagist上后,就可将本地项目composer.json
添加的repositories
移除,重新运行composer install
,
来安装packagist上的版本,同时packages
目录亦可删除。
版本问题说明
composer使用语义化的版本进行依赖管理,因此类库在更新和发布时,所标记的版本号,也就当遵循语义化的版本规范。
基主要有以下几个内容:
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
- 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
参考资料
GitLab-CI实现自动化测试
GitLab-Ci实现自动化测试
持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
使用自动化测试, 可以提高软件的质量和可靠性, 今早发现其中的缺陷和问题, 以便即时改正.
配置环境
首先需要一个满足运行自动化测试的Docker镜像, 以便后面运行测试代码, 例如:
1 | image: zacksleo/docker-composer:develop |
配置服务
某些测试需要使用额外的服务, 如数据库、缓存服务器等等, 并通过variables
配置服务中的一些变量
1 | services: |
声明依赖工件
一般在测试前要进行准备过程, 如安装依赖库或者编译等, 可将上述过程生成的的文件, 通过依赖声明, 传递过来, 这样可以比避免重复执行相关过程.
1 | installing-dependencies: |
1 | dependencies: |
配置测试脚本
假定你已经在本地编写好了测试代码, 并且可以本地运行, 那么就可以通过调整和适配, 让测试可以在GitLab-CI中自动化执行, 在下面的例子中,
测试代码位于tests
目录,并且.env
中配置了一些环境变量, 该文件的作用是为了让不同环境使用不同的一组变量, 如数据库、接口地址、账号等等,
这样做的目录可以尽量少的变更代码,保持核心代码的稳定性和适应能力, 通过php -S
启动了一个本地接口服务, 最后调用api测试, 对所有接口
进行测试
在下面的例子中, 还声明了coverage
, 这个用来说明代码测试覆盖率的取得方法, 因为在测试中会将覆盖率输出(--coverage --no-colors
),
GitLab-CI 通过正则匹配输出内容, 读取到覆盖率, 从而显示在项目徽标处
1 | dependencies: |
测试失败如何处理
当测试失败后, 除了查看Pipline
中的任务输出, 我们还应当详细查看测试中的相关日志, 下面这里, 将需要查看的文件生成工件, 在GitLab中下载,
然后可以在本地详细查看, when
说明了仅在测试失败时, 才生成工件
1 | artifacts: |
完整的例子
下面是一个完整的API自动化测试的盒子
api-test:
stage: testing
services:
- mysql:5.6
- redis:latest
variables:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: web
MYSQL_USER: web
MYSQL_PASSWORD: web
dependencies:
- installing-dependencies
script:
- cp tests/.env .env
- ./yii migrate/up --interactive=0
- php -S localhost:80 --docroot api/tests &>/dev/null&
- ./vendor/bin/codecept run api -c tests
artifacts:
name: "debug"
when: on_failure
untracked: true
expire_in: 60 mins
paths:
- $CI_PROJECT_DIR/api/runtime
- $CI_PROJECT_DIR/tests/_output
only:
- develop
- master
关于持续集成完整的项目, 请查看 zacksleo/yii2-app-advanced 项目
如何编写GitLab-CI配置文件
创建文件
在根目录新建.gitlab-ci.yml
文件.
该文件与项目其他文件一样, 同样受到版本控制, 所以可以在不同的分支下, 配置不同的持续集成脚本
YAML语法
配置文件遵循YAML语法, 关于该语法的内容, 自行搜索
参考 YAML 语言教程
关键词
根主要关键词一览
关键词 | 含义 | 可选 | 备注 |
---|---|---|---|
image | 声明使用的Docker镜像 | 为空时使用默认镜像 | 该镜像应当满足脚本执行的环境依赖 |
services | Docker镜像使用的服务, 通过链接的方式来调用所需服务 | 可空 | 常用于链接数据库 |
stages | 定义构建阶段 | 为空时, 单纯定义jobs | 项目的构建分为多个阶段, 例如: 安装依赖/准备, 编译, 测试, 发布等, 同时每个阶段包含若干任务 |
before_script | 定义每个job之前执行的脚本 | 可空 | 每个job启动时会先执行该脚本 |
after_script | 定义每个job之后执行的脚本 | 可空 | 同上 |
variables | 定义变量 | 可空 | 同上 |
cache | 定义与后续job之间应缓存的文件 | 可空 | 同上 |
Demo:
1 | image: aipline |
Jobs中的关键词
jobs中存在一些与根中相同的关键词, 这些一旦定义, 则会向前覆盖, 即根中定义的则不会在该job执行
job 这里译为任务
关键词 | 含义 | 可选 | 备注 |
---|---|---|---|
image | 声明任务使用的Docker镜像 | 为空时使用根中的定义 | 该镜像应当满足脚本执行的环境依赖 |
services | 任务中Docker镜像使用的服务, 通过链接的方式来调用所需服务 | 可空 | 常用于链接数据库 |
stage | 所属构建阶段 | 为空时则不使用stages | 一个任务属于一个构建阶段 |
before_script | 定义每个job之前执行的脚本 | 可选 | 如果在job中定义则会覆盖根中的内容 |
script | 定义每个job执行的脚本 | 必须 | |
after_script | 定义每个job之后执行的脚本 | 可选 | 同上 |
variables | 定义任务中使用的变量 | 可选 | 同上 |
cache | 定义与后续job之间应缓存的文件 | 可选 | 同上 |
only | 指定应用的Git分支 | 可选 | 可以是分支名称, 可用正则匹配分支, 也可是tags来指定打过标签的分支 |
except | 排除应用的Git分支 | 可选 | 同上 |
tags | 指定执行的GitLab-Runners | 可选 | 通过匹配Runners的标签选定 |
allow_failure | 允许失败 | 默认为false | 如果允许失败, 本次任务不会影响整个构建的结果 |
when | 定义合适执行任务 | 默认为always | 有on_success , on_failure , always or manual 可选 |
dependencies | 定义合任务所需要的工件 | 可空 | 需要首先定义工件 |
artifacts | 定义工件 | 可空 | 工件中指定的目录会在任务执行成功后压缩传到GitLab, 后面需要该工件的任务执行时, 再自行下载解压 |
environment | 定义环境 | 可空 | 在部署任务中, 定义该任务所属的环境 |
Demo:
1 | installing-dependencies: |
注意:
- jobs的名称不能重名
- 同一阶段中的任务, 是并行执行的
- 上一阶段所有任务执行完后, 才会进入下一阶段
- 定义工件时, 务必定义工件的过期时间, 否则工件会一直寸在GitLab上, 占用空间
- 如果需要在任务中传递文件, 优先选择使用
dependencies
(结合artifacts
)
验证配置文件合法性
在GitLab中, 打开 /ci/lint
网址, 将配置文件粘贴在些, 进行验证
相关文档
GitLab-CI快速开始
假定已经安装好了
GitLab-Runners
Hello World !
在仓库根目录创建 .gitlab-ci.yml
文件, 内容如下
1 | job-1: |
这样, 在每次提交代码后, 都会自动执行以上脚本. 其中job-1
是任务名称, 可以定义多个任务,
script
下面是 shell 命令, 只要命令执行成功, 就代表本次构建通过(出现passed标记)
如图
这样, 一次简单的持续集成已经搞定了.
远程拉取代码
使用ssh远程登录服务器, 然后执行git pull
拉取代码, 实现代码热更新
由于ssh无密码登录需要用到密钥, 所以首先需要注入私钥
如
1 | release-doc: |
一个更详细的例子 [[通过gitlab-ci实现文件的自动部署]]
通过Docker镜像实现自动部署
见文章 [[GitLab-CI使用Docker进行持续部署]]
参考资料
GitLab-CI简介
概述
持续集成(CI)和 持续交付(CD) 是一种流行的软件开发实践,每次提交都通过自动化的构建(测试、编译、发布)来验证,从而尽早的发现错误。
持续集成实现了DevOps, 使开发人员和运维人员从繁琐的工作中解放出来。另外,这种形式极大地提高了开发者的开发效率和开发质量。
持续集成有多种工具,如Jenkins. GitLab内置了GitLab-CI,通过配置一段YAML
脚本来实现持续集成.
功能
持续集成可以实现的功能:
- 代码审核: 自动化代码规范审查, 甚至代码质量检查
- 自动化测试: 单元测试, 功能测试和验收测试
- 编译发布: 将源代码编译成可执行程序, 并将程序上传到托管发布平台实现自动发布
- 构建部署: 通过构建Docker镜像, 或登录远程服务器执行相关部署命令和脚本, 实现自动化部署
原理
GitLab-CI 检测每次代码变动, 通过.gitlab-ci.yml
脚本执行构建命令, 将命令发布到GitLab-Runners(运行机)
上, 进而执行命令.
GitLab-Runners
基于Docker执行持续集成的每项任务, 这样就解决了环境依赖问题.
GitLab-Runners
把实时将执行结果输出到GitLab网页上, 任务执行完后, 通过徽章标记和邮箱告知执行结果.
下一章: [[GitLab 快速开始]]
GitLab-CI使用Docker进行持续部署
Docker镜像通过私有仓库进行发布(如阿里云), 发布命令为:
1 | docker login -u username -p password registry.demo.com |
其中 username
是用户名, password
是密码, registry.demo.com
是私有镜像库地址,
$CI_PROJECT_NAME
是GitLab-CI内置变量, 会自动替换为项目的名称, 这里也可以直接写死, 如
docker build -t registry.demo.com/repos/image-name:latest .
image-name
, 就是要构建的镜像名称, latest
是TAG标签, repos
是仓库的空间名称
在下面的例子中, 首先通过composer安装依赖库, 然后通过artifacts传递给构建任务, 构建完镜像将镜像发布到私有库,
部署时通过拉取最新的镜像库, 进行部署
项目的deploy目录中, 放置一些配置文件, 如
Dockerfile
,docker-compose.yml
等, 通过rsync
同步到部署服务器上, 用于部署所需
1 | image: zacksleo/docker-composer:1.1 |
相关文档
GitLab-CI中的artifacts使用研究
在GitLab-CI中, cache
与artifacts
比较容易混淆.
其中 cache
指的是缓存, 常用于依赖安装中, 如几个jobs
都需要安装相同的依赖, 可以使用依赖
, 此时可以加快依赖的安装进度;
对于artifacts
则是将某个工件
上传到GitLab提供下载或后续操作使用, 由于每个job
启动时, 都会自动删除.gitignore
中指定的文件, 因此对于依赖安装目录, 即可以使用cache
, 也可以使用artifacts
.
两个主要有以下几个区别:
cache
不一定命中,artifacts
肯定命中, 能否使用cache
取决当当前机器是否生成过cache, artifacts则每次都会从GitLab下载- 重新安装时因为使用的是缓存, 所以很有可能不是最新的
- 特别是开发环境, 如果每次都希望使用最新的更新, 应当删除
cache
, 使用artifacts
, 这样可以保证确定的更新
4.artifacts
中定义的部分, 会自动生成, 并可以传到下面的job
中解压使用, 避免了重复依赖安装等工作 - 如果使用Docker运行Gitlab-Runner,
cache
会生成一些临时容器, 不容易清理 artifacts
可以设置自动过期时间, 过期自动删除,cache
不会自动清理artifacts
会先传到GitLab服务器, 然后需要时再重新下载, 所以这部分也可以在GitLab下载和浏览
artifacts
的依赖使用
下面是一个使用artifacts
的例子, 首先有一个安装依赖的工作, 然后工作完成后, 会将安装文件转移到后续的工作时
1 | installing-dependencies: |
如果上述过程使用cache
, 则会变成下面这样子, 注意, 此时每次都要执行composer install
这样的依赖安装工作, 即before_script
1 | cache: |
或
1 | cache: |
否则, 会出现类似 vendor not found
的问题
禁用artifacts
默认artifacts会自动在不同的stage中传输, 如果该stage中的job不需要artifacts, 则可以禁用artifacts, 以加速构建速度
1 | dependencies: [] |
注意
使用
cache
会出现一个问题, 就是缓存有可能使用上次执行该job
时的缓存, 不能保证某些文件最新
相关文档
GitLab-CI通过ssh进行自动部署
需求
通过gitlab-ci实现文件的自动部署
实现过程
文档托管在gitlab上, 每次代码更新, 会自动出发gitlab-ci构建
在构建脚本中, 通过ssh 登录远程服务器执行git拉取文档的命令
过程
首先需要在服务器上生成ssh证书
注意该证书的用户必须与ssh远程登录的用户一样, 例如我们的用户名是root
将公钥添加到gitlab上, 以便于该用于可以拉取代码
在 CI/CD Piplines
中设置 Secret Variables
, 包括 DEPLOY_SERVER
和 SSH_PRIVATE_KEY
其中 SSH_PRIVATE_KEY
的内容是服务器上的私钥, DEPLOY_SERVER
是服务器地址
编写 .gitlab-ci.yml
文件, 注入密钥, 通过ssh
执行远程命令
完整代码
1 | # 使用alpine镜像, 该镜像很少,只有几兆 |