进阶篇 | 有了这招,用文本编辑器搞前端代码都能保证格式统一

上一篇文章中,结合节点库已有节点,建木CI以一个相对简单的流程DSL为大家展示了prettier节点的基本用法。

图片

通过预览管道,可以看出流程总共被分成三个部分:

  1. 将代码从远程仓库克隆下来

  2. 对整个项目文件全部进行格式化

  3. 将格式化后的代码重新推送到远程仓库

确实,如果只单纯的对远程仓库中的代码进行格式化,上次的流程完全可以解决。但如果将它运用到真正的项目开发过程中的话那就显得差点意思。对于基础篇的流程来说,它只会在代码push到远程仓库才被触发。并且每次流程被执行时,prettier节点都会全盘的对这个项目下的所有文件进行格式化,即使对于一个没有任何改动的文件也是如此。

图片

prettier前端代码格式化流程在项目中的应用

在解决上面流程中提到的不足点之前,首先我们要搞清楚在真实项目开发过程中,哪些场景下是有必要做代码格式化的?其实在大多情况下,通过Git代码托管平台例如:gitee、github来进行代码管理时,我们只需要保证每一次push的代码以及在合并Pull Request(以下简称pr)时原分支的代码都是符合统一规范的代码即可。

  • 为项目的webhook添加Pull Request事件钩子

在上篇文章中我们为仓库配置了webhook,并指定了在push操作后触发流程。为了达到上述需求,我们还需要在仓库webhooks的选择事件里勾选Pull Request。这样在仓库进行pr操作时也会触发格式化流程。

图片

  • 利用jsonpath、pr-file-diff节点提取需要进行格式化的文件路径信息

该如何避免在每一次流程中,prettier节点对整个项目进行格式化?参考prettier节点的使用说明可以知道,输入参数files中里可以具体指定需要格式化的文件,节点内部会循环查找对应的文件并格式化。如何才能拿到这些信息呢?不用着急,基于节点库中已有的jsonpathpr-file-diff节点,现在可以非常方便的在push跟pr操作中提取到文件的变动信息。

图片

复制下面的DSL,对之前代码格式化流程做一个升级。

name: prettier节点测试
description: prettier格式化前端代码

trigger:
  type: webhook
  param:
    # webhook响应头中的token值
    - name: gitee_token
      type: SECRET
      exp: $.header.x-gitee-token
    # gitee中的webhook钩子事件
    - name: gitee_event
      type: STRING
      exp: $.header.x-gitee-event
    # 仓库项目名
    - name: project_name
      type: STRING
      exp: $.body.json.project.name
    # 此次提交pr的地址
    - name: pr_url
      type: STRING
      exp: $.body.json.url
    # push操作,此次提交的文件修改的信息
    - name: trigger_data
      type: STRING
      exp: $.body.json.commits
    # webhook返回的分支信息
    - name: gitee_ref
      type: STRING
      exp: $.body.json.ref
    # 提交pr的原分支
    - name: source_branch
      type: STRING
      exp: $.body.json.source_branch
    # 提交pr的目标分支
    - name: target_branch
      type: STRING
      exp: $.body.json.target_branch
    # 提交的commit信息
    - name: commit_message
      type: STRING
      exp: $.body.json.commits[0].message
    # 获取pr操作时的仓库地址
    - name: pr_repository_url
      type: STRING
      exp: $.body.json.source_repo.project.git_http_url
    # 获取push操作时的仓库地址
    - name: push_repository_url
      type: STRING
      exp: $.body.json.repository.git_http_url
    # 项目的fullName
    - name: project_full_name
      type: STRING
      exp: $.body.json.project.full_name
    # pr用户
    - name: pr_user
      type: STRING
      exp: $.body.json.author.name
    # push用户
    - name: push_user
      type: STRING
      exp: $.body.json.pusher.name
    # 获取pr操作时的仓库html地址
    - name: pr_repository_html_url
      type: STRING
      exp: $.body.json.source_repo.project.html_url
    # 获取push操作时的仓库html地址
    - name: push_repository_html_url
      type: STRING
      exp: $.body.json.repository.html_url
    # webhook行为描述
    - name: action_desc
      type: STRING
      exp: $.body.json.action_desc
  # 控制流程只在对仓库master分支进行push操作和新建pr时触发
  only: >
    (${trigger.gitee_event} == "Merge Request Hook" && ${trigger.pr_repository_url} != "https://gitee.com/oschina/git-osc" && ${trigger.action_desc} == "open" && ${trigger.pr_repository_url} == ${trigger.push_repository_url} || (${trigger.gitee_event} == "Push Hook" && ${trigger.gitee_ref} == "refs/heads/master" && ${trigger.commit_message} != "refactor: auto format code"))
workflow:
  start:
    type: start
    alias: 开始
    targets:
      - string_repository_url
      - string_repository_branch
  string_repository_url:
    type: string:1.0.0-nodejs16.13.1
    alias: 获取仓库地址
    sources:
      - start
    targets:
      - git_clone
    param:
      expression: >
        "${trigger.gitee_event}" === "Merge Request Hook" ? "${trigger.pr_repository_url}" : "${trigger.push_repository_url}"
  string_repository_branch:
    type: string:1.0.0-nodejs16.13.1
    alias: 获取仓库分支
    sources:
      - start
    targets:
      - git_clone
    param:
      expression: >
        "${trigger.gitee_event}" === "Merge Request Hook" ? "refs/heads/${trigger.source_branch}" : "${trigger.gitee_ref}"
  git_clone:
    type: git_clone:1.2.1
    alias: 克隆项目
    sources:
      - string_repository_url
      - string_repository_branch
    targets:
      - isPushRequest
    param:
      remote_url: ${string_repository_url.result}
      ref: ${string_repository_branch.result}
      username: ((gitee.comyan_username))
      password: ((gitee.comyan_password))
  isPushRequest:
    type: condition
    alias: 是否为push
    sources:
      - git_clone
    expression: ${trigger.gitee_event} == "Push Hook"
    cases:
      true: jsonpath
      false: pr_file_diff
  jsonpath:
    type: jsonpath:1.0.0
    alias: 提取变动的文件路径列表
    sources:
      - isPushRequest
    targets:
      - string_push
    param:
      expression: "$..['modified,added']"
      data: '${trigger.trigger_data}'
  string_push:
    type: string:1.0.0-nodejs16.13.1
    alias: 构造prettier输入参数
    sources:
      - jsonpath
    targets:
      - condition_push
    param:
      expression: >-
        JSON.stringify(${jsonpath.result}.map(arr=>arr.map(item=> '${git_clone.git_path}' + '/' + item )).flat(2))
  condition_push:
    sources:
      - string_push
    alias: 判断文件列表是否为空
    type: condition
    expression: ${string_push.result}=="[]"
    cases:
      true: end
      false: prettier_push
  pr_file_diff:
    type: gitee:1.0.0-pr-file-diff
    alias: 提取变动的文件路径列表
    sources:
      - isPushRequest
    targets:
      - string_pr
    param:
      access_token: ((gitee.comyan_git_token))
      pr_url: ${trigger.pr_url}
  string_pr:
    type: string:1.0.0-nodejs16.13.1
    alias: 构造prettier输入参数
    sources:
      - pr_file_diff
    targets:
      - condition_pr
    param:
      expression: >-
        JSON.stringify(JSON.parse('${pr_file_diff.diff}').map(item => "${git_clone.git_path}" + "/" + item.filepath ).filter(item=>item))
  condition_pr:
    sources:
      - string_pr
    alias: 判断文件列表是否为空
    type: condition
    expression: ${string_pr.result}=="[]"
    cases:
      true: end
      false: prettier_pr
  prettier_push:
    type: prettier:1.0.0-2.5.1
    alias: 格式化
    sources:
      - condition_push
    targets:
      - git_push
    param:
      files: ${string_push.result}
      config_path: ${git_clone.git_path}/peizhi.js
  prettier_pr:
    type: prettier:1.0.0-2.5.1
    alias: 格式化
    sources:
      - condition_pr
    targets:
      - git_push_pr
    param:
      files: ${string_pr.result}
      config_path: ${git_clone.git_path}/peizhi.js
  git_push:
    type: git_push:1.0.4
    alias: push格式化代码
    sources:
      - prettier_push
    targets:
      - end
    param:
      remote_url: ${string_repository_url.result}
      remote_branch: ${git_clone.git_branch}
      username: ((gitee.comyan_username))
      password: ((gitee.comyan_password))
      source_path: ${git_clone.git_path}
      target_dir: ${trigger.project_name}
      commit_message: "refactor: auto format code"
  git_push_pr:
    type: git_push:1.0.4
    alias: push格式化代码
    sources:
      - prettier_pr
    targets:
      - end
    param:
      remote_url: ${string_repository_url.result}
      remote_branch: ${trigger.source_branch}
      username: ((gitee.comyan_username))
      password: ((gitee.comyan_password))
      source_path: ${git_clone.git_path}
      target_dir: ${trigger.project_name}
      commit_message: "refactor: auto format code"
  end:
    type: end
    alias: 结束
    sources:
      - git_push
      - git_push_pr
      - condition_push
      - condition_pr

点击项目的预览流程按钮

从流程预览图中可以看出,push跟pr操作被分为两个不同分支,并且在prettier节点被触发之前,我们已对此次操作中存在变动的文件信息做了单独的提取。

接下来分别对push和pr两个场景进行测试

  • 本地主分支push代码

等待流程执行成功,可以看见这次prettier节点只对有变化的文件进行了代码格式化。

  • 本地非主分支push代码

在comyan分支下修改222.js文件

可以看见代码被推送到comyan分支下,但是此次操作并没有触发流程。

通过查看项目的webhook请求记录,可以发现这次请求状态是失败的。点击详情具体看看是什么原因造成的?

查看触发器参数值可以发现,流程only表达式中指定的gitee_ref跟此次webhook请求返回的gitee_ref不匹配,流程执行被限制。

  • 新建pr合并不同分支代码

流程执行pr分支

等待流程执行成功,刷新页面,可以发现在此次pr的提交里新增了一条refactor: auto format code记录。

之前在comyan分支下修改的文件在提交pr的时被自动格式化

经过上面3个场景的演示,你可能能够理解为什么在流程中我们对非主分支下push代码的操作做了条件限制。在通过新建pr对不同分支进行代码合并时,流程会对原分支代码格式化。加上这种机制,它可以减少流程被触发的次数。

本文为建木博主「comyan」的原创投稿文章,转载请联系授权。

项⽬官⽹:https://jianmu.dev

项⽬托管:https://gitee.com/jianmu-dev

项⽬文档:https://docs.jianmu.dev

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值