写点什么

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

作者:Jianmu
  • 2022 年 4 月 12 日
  • 本文字数:4651 字

    阅读完需:约 15 分钟

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

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



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

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

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

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

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



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

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

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

在上篇文章中我们为仓库配置了 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

用户头像

Jianmu

关注

国产开源CI/CD产品 2020.08.10 加入

建木持续集成平台基于建木,致力于为国内开发者与DevOps人员提供极致用户体验,提升开发、上线、运维的效率,让软件用户专注于提供业务价值。

评论

发布
暂无评论
进阶篇|有了这招,用文本编辑器搞前端代码都能保证格式统一_运维_Jianmu_InfoQ写作平台