记一次使用 CI 的开源项目开发

项目地址:https://github.com/CaoMeiYouRen/super-search-hub

本项目开源在 GitHub 上。因为 travis-cidocker 都只对开源项目免费,索性就直接开源了。

项目本身倒是没必要多提,本次还是想聊聊持续集成的那些事情。

dependabot

dependabot是 GitHub 推出的一个提醒依赖更新机器人,当你项目的依赖有更新的时候就会自动推送一个 Pull requests

travis-ci

travis-ci 是一个知名的 CI 工具,只需要在项目根目录下编写 .travis.yml 文件即可,例如

language: node_js
node_js: 12.15.0
services:
    - docker
install:
    - npm install
script:
    - npm run lint
    - npm run build
deploy:
    provider: script
    skip_cleanup: true
    on:
        branch: master
    script:
        - npm run release
cache:
    directories:
        - node_modules
notifications:
    webhooks:
        urls:
            # 钉钉
            - secure: pCBLuzxjzjdLTHZhse4z66lQJsyrklML1lPfwZSQfgBJLMteyrY9bXqH0uXxzw7UpnFvFQRZjOanDQh+78M1U43PoXzGzONcRc8FTMOSGgCiLd7w7ZNaKaBP+uCzvnS2Y0uHZpZcb0QxCvLTBMQGpO6NztcDTYAoVmWtok0/IwNdHI45Bh4kefNT5L9WE2M09R9J7dLI42feHzNyf7iSHEEJTOi7V5v++FdnRzdA+Vy/UtESpN4RviAJ4E/FXMQhuJ6ili9w/P4qPBJyMTtn9XxRmkSXP+UIwWNoojl/UcbnAKFVywcQzQkyfqe4grz1xmeyoSDX/PopMwpok+/N7pBY4/UWz8k16GlISOifME5MfZ/SHhP5BS/yYV5Pih8iHwMaM0gqXIo2nuBVdBF7pB3058zbIovM0v2FSg3wV2z+4PLeS4UsWaxt5Iqpq0YoWvkOmCMB8aqP1acqCKplkqNw3sU3WJ7mIU8xTd9U5PPYGHeF86h+BLMdz8nYHI8n8n1muKUMaW8MZ4G7jLlOX31Fx07VVjAOAhj0rWAz9qVOKjZFhFh+HmaBgY84zR6zQzZnNtD42vsaNrbKkXsOIrc7cSDdAkkM/7xUeOl+Y0Inr5ElALTpKz5oem7P0M1AN2Z/IAYVYuI9Sre0uFEsbnPbGZ54c7s5/k2r4WFztMk=

在这里着重要提的就是加密配置中的关键字段了。

需要先下载 travis-cli ,下载方式见文档。需要 Ruby 环境,自行下载即可。

gem install travis
travis version #检查是否安装成功

另外,gem 在国内访问也是慢的要死,配置一下国内镜像即可

接下来就是登陆了

travis login --com

此处有一个惊天大坑,那就是 travis-ci.com、travis-ci.org 是同一家公司的两个网站。本来是一个用于商用,一个用于开源,但后来合并了,目前使用的是 travis-ci.com。

但是登陆时默认使用的是 api.travis-ci.org 而不是 api.travis-ci.com 因此需要添加 --com来切换源

后面的看文档就行了

travis encrypt FOO=bar #FOO=bar就是要加密的东西

使用时添加为- secure字段就行

semantic-release

本项目的 release 部分使用了 semantic-release。这是一个挺好用的 release 工具

只需要在项目根目录下新建一个 .releaserc.js 文件即可,例如

module.exports = {
    plugins: [
        [
            '@semantic-release/commit-analyzer', // 解析git commit,如果要自动生成日志那么是必须的
            {
                config: 'conventional-changelog-cmyr-config',
            },
        ],
        [
            '@semantic-release/release-notes-generator', // 生成 git release
            {
                config: 'conventional-changelog-cmyr-config',
            },
        ],
        [
            '@semantic-release/changelog', //生成更新日志
            { 
                changelogFile: 'CHANGELOG.md', //日志路径
                changelogTitle: '# super-search-hub', //日志标题
            },
        ],
        '@semantic-release/npm', //如果是npm模块建议引入,可以自动更新版本号。如果要自动发布则需要NPM_TOKEN
        '@semantic-release/github', //需要 GH_TOKEN 来验证权限
        [
            '@semantic-release/git', // 推送生成的文件回到GitHub。
            {
                assets: [
                    'dist',
                    "docs",
                    'CHANGELOG.md',
                    'package.json',
                ],
            },
        ],
        [
            '@semantic-release/exec', //执行 release 命令
            {
                prepareCmd: 'npm run docs:build && docker build -t caomeiyouren/super-search-hub .',
            },
        ],
        [
            'semantic-release-docker', // 发布到docker。需要配置 DOCKER_USERNAME 和DOCKER_PASSWORD。在travis网站上配置环境变量就行
            {
                name: 'caomeiyouren/super-search-hub',
            },
        ],
    ],
}

cz-conventional-changelog

包括 commitizen、cz-conventional-changelog、conventional-changelog-cli、conventional-changelog-cmyr-config。最后一个是日志格式,可以自定义。

下面来具体说明下如何实现自动化生成日志。

首先,要生成日志,那么必须对 git commit 做风格约束。因此使用 commitizen、cz-conventional-changelog 来提交日志。

在 package.json 文件中配置

  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }

之后使用 git cz 即可提交符合要求的 git commit

除此之外,为了防止有人不按规矩来,使用 husky、validate-commit-msg 来校验提交的 git commit 是否符合格式

当提交完 git commit 后,执行

conventional-changelog -p cmyr-config -i CHANGELOG.md -s -r 0

来生成日志。

当然如果使用了 CI 就没有这一步了,生成日志这种活也应该交给 CI

jenkins

本项目还有一个需求,那就是当 travis-ci 编译完成后通知自己的服务器进行部署。

自建的 CI 选择了 jenkins,jenkins 也提供了 webhook 来触发部署。

但在这里遇到了一个问题。

最新版的 jenkins 对于 CSRF (跨站请求伪造) 进行了防护,请求中必须带有 crumb 才行,直接访问是 403 的。

经过一番搜寻后找到了解决方法。既然无法直接访问的话那就自己写个中转吧。

async function jenkinsAPI(url: string, query: any = {}, data: any = {}, method: any = 'GET') {
    const jenkinsAxios = axios.create({
        baseURL: 'https://xxx.yyy.zzz',
        auth: {
            username: JENKINS.JENKINS_USERNAME,
            password: JENKINS.JENKINS_PASSWORD,
        },
    })

    const crumbIssuer = await jenkinsAxios.get('/crumbIssuer/api/json')
    const result = await jenkinsAxios(url, {
        method,
        params: query,
        data,
        headers: {
            'Content-Type': 'application/json',
            [crumbIssuer.data?.crumbRequestField]: crumbIssuer.data?.crumb,
            Cookie: crumbIssuer.headers['set-cookie'][0],
        },
        timeout: 10000,
    })
    return result
}

调用这个函数即可

webpack

本项目使用 webpack 来打包,生成的 dist 文件只需要有 node 环境就能运行,无需安装任何依赖。再结合 docker 技术,就生成了一个体积极小的镜像。主要体积是 node.js 这个运行时,代码部分极小

docker

docker 在本项目中用于部署。

话说回来,既然本项目已经使用 webpack 来打包了,只有一个 dist/index.js 文件用于部署,可以讲是非常方便了,那么为什么还是要用 docker?

要说原因的话还是因为 docker 部署比真机部署更加方便,更新起来也更加方便。

同时 docker 部署下运行环境都是一致的,而真机可能会因为种种原因导致 node.js 的版本不一样(尤其是在版本更迭极快的今天)。同时 docker 也能一键解决依赖问题。所以还是更加推荐 docker 部署。

顺便附上一个我用的部署命令行

/usr/bin/docker-compose stop
if [ $? -ne 0 ];then
    echo -e "${red} 停止旧容器失败 ${font}"
fi

#删除所有(停止状态的)服务容器和镜像,为了保证重新拉取镜像
/usr/bin/docker system prune -a -f
if [ $? -ne 0 ];then
    echo -e "${red} 删除旧容器失败 ${font}"
fi

/usr/bin/docker-compose up -d --build
if [ $? -ne 0 ];then
    echo -e "${red} 启动新容器失败 ${font}"
fi

评论

发表回复