最近快溜了, 记录一下之后可能复用到的东西, 之前记录过关于 gitlab 部署与钉钉集成, 但是没有设计到流水线, 仅仅只是仓库信息提交之类的. 这里记录一下 机器人 关于流水线提交的实现.

实现效果

预览图

基础仓库

新建一个仓库为 share/gitlab-ci, 其中存储一个 dingtalk.yml, 内容为以下, 基本实现功能为在 gitlab 提供的 hook 时机下使用 curl 通知 钉钉

# 钉钉消息发送模版任务
# 必须变量
# DINGTALK_ACCESS_TOKEN 群机器人token

variables:
  # 钉钉markdown换行符 必须\n且前后跟两个空格(shell 转义)
  V_BR: "\ \ \\n\ \ "

# 消息发送准备工作
# 检测钉钉消息发送access_token是否存在
.prepare: &prepare
  # token检验
  - |
    if [ -z $DINGTALK_ACCESS_TOKEN ]; then
      echo "使用钉钉消息发送必须配置DINGTALK_ACCESS_TOKEN变量"
      exit 1
    fi
  # url编码项目地址及任务地址
  - |
    project_url="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "${GITLAB_URL}/${CI_PROJECT_PATH}/-/tree/${CI_BUILD_REF_NAME}" "" || true)"
    job_url="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "${GITLAB_URL}/${CI_PROJECT_PATH}/-/jobs/${CI_JOB_ID}" "" || true)"
    nowTime=$(date +'%Y年%m月%d日 %H:%M')

# 钉钉消息发送http Anchors
.send_request: &send_request
  # Markdown消息内容
  - |
    V_TEXT="**${CI_PROJECT_NAME} 任务<font color=\\\"${V_COLOR}\\\">${V_STATUS}</font>通知**${V_BR}\
    任务ID: **${CI_JOB_ID}**${V_BR}\
    任务名: **${CI_JOB_NAME}**${V_BR}\
    提交信息: ${CI_COMMIT_MESSAGE}${V_BR}\
    项目: **${CI_PROJECT_PATH}**${V_BR}\
    分支: **${CI_BUILD_REF_NAME}**${V_BR}\
    执行人: **${GITLAB_USER_NAME}**${V_BR}\
    时间: **${nowTime}**${V_EXTRA}\
    "
  # 钉钉消息发送json报文
  - |
    V_JSON="{
      \"actionCard\": {\
            \"title\": \"${V_TITLE}\",\
            \"text\": \"${V_TEXT}\", \
            \"btnOrientation\": \"1\",\
            \"btns\": [{\
               \"title\": \"查看项目\",
               \"actionURL\": \"dingtalk://dingtalkclient/page/link?url=${project_url##/?}&pc_slide=false\"
             }, {\
              \"title\": \"查看任务\",
              \"actionURL\": \"dingtalk://dingtalkclient/page/link?url=${job_url##/?}&pc_slide=false\"
            }]\
        },\
        \"msgtype\": \"actionCard\"\
    }"
  - >
    curl -s -H 'Content-Type: application/json; charset=utf-8' -X POST 
    https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_ACCESS_TOKEN} -d "${V_JSON}" -w "\n"

# 消息发送模板任务
.dingtalk:
  # 发送ci开始消息
  before_script:
    - *prepare
    - |
      V_COLOR="#FF9900"
      V_STATUS="启动"
      V_TITLE="CI任务启动通知"
    - *send_request

  # 发送ci结束消息
  after_script:
    - *prepare
    # 不同任务状态设置不同消息标题、颜色
    - |
      case $CI_JOB_STATUS in
        success)
          V_TITLE="CI任务执行成功通知"
          V_STATUS="执行成功"
          V_COLOR="#33CC00"
          ;;
        failed)
          V_TITLE="CI任务执行失败通知"
          V_STATUS="执行失败"
          V_COLOR="#FF3333"
          ;;
        *)
          echo "不支持job状态${CI_JOB_STATUS}"
          exit 1
          ;;
      esac
    # 执行耗时计算
    - |
      start_time=`date -d ${CI_JOB_STARTED_AT} "+%Y-%m-%d %H:%M:%S"`
      seconds=$(($(date +%s) - $(date +%s -d "${start_time}")))
      V_EXTRA="${V_BR}耗时: **$[seconds/60]分$[seconds%60]秒**"
    - *send_request

流水线 yml 文件

这里主要使用了其他的一个仓库, 依赖了一个其他仓库中的 yml 文件dingtalk.yml

# 模板文件引入
include:
  - project: share/gitlab-ci
    ref: master
    file: dingtalk.yml

# 对应值为刚刚复制的 access_token
# 全局变量 若需要每个任务发送不同的钉钉群 将变量定义在job中
variables:
  IMAGE_FULL_NAME: ${CI_PROJECT_NAME}:latest
  IMAGE_TAG_NAME: ${CI_PROJECT_NAME}-${CI_COMMIT_TAG}

stages:
  - check
  - build
  - build_tag
  - deploy_test
  - deploy_production
# 代码检查
check:
  # 模板任务继承
  extends: .dingtalk
  stage: check
  when: always
  script:
    - echo '代码检查相关脚本 yarn lint'
    - echo "安装依赖"
  tags:
    - bash
# 代码 build
build:
  # 模板任务继承
  extends: .dingtalk
  stage: build
  when: always
  allow_failure: false
  script:
    - docker build -t $IMAGE_FULL_NAME .
    - echo "推送远程的镜像仓库"
  artifacts:
    name: gtsp-server
    paths:
      - ./
    exclude:
      - .git/**/*
      - .vscode/**/*
    untracked: true
    expire_in: 1 week
  tags:
    - ssh-bash
build_tag:
  # 模板任务继承
  extends: .dingtalk
  stage: build_tag
  when: always
  rules:
    - if: $CI_COMMIT_TAG
  allow_failure: false
  image:
    name: docker:stable
    pull_policy: "if-not-present"
  script:
    - npm i -g node-prune --registry=https://registry.npmmirror.com/
    - npm i -g cnpm --registry=https://registry.npmmirror.com/
    - cnpm i --omit=dev --registry=https://registry.npmmirror.com/
    - npm run build
    - node-prune
    - docker build --no-cache -t $IMAGE_TAG_NAME .
    - docker images
    # - docker push $IMAGE_FULL_NAME
    - echo "推送远程的镜像仓库"
    # - docker rmi $IMAGE_FULL_NAME
    - echo "删除本地镜像"
  tags:
    - docker-gtsp-server
# 部署开发服务器
deploy_test:
  # 模板任务继承
  extends: .dingtalk
  stage: deploy_test
  when: always
  only:
    - test
  script:
    - echo "登录到生产服务器"
    - echo "docker login"
    - echo "docker pull 拉区对应镜像的版本号"
    - echo "更改对应镜像的版本号"
    - echo "修改 docker-compose 的版本号"
    - echo "执行 docker-compose up -d 应用最新的版本"
  tags:
    - bash