在上一篇文章中,结合节点库已有节点,建木CI以一个相对简单的流程DSL为大家展示了prettier节点的基本用法。
通过预览管道,可以看出流程总共被分成三个部分:
- 将代码从远程仓库克隆下来
- 对整个项目文件全部进行格式化
- 将格式化后的代码重新推送到远程仓库
确实,如果只单纯的对远程仓库中的代码进行格式化,上次的流程完全可以解决。但如果将它运用到真正的项目开发过程中的话那就显得差点意思。对于上一篇的流程来说,它只会在push代码到远程仓库才被触发,并且每次流程被执行时,prettier节点都会全盘的对这个项目下的所有文件进行格式化,即使对于一个没有任何改动的文件也是如此。
prettier前端代码格式化流程在项目中的应用
在解决上面流程中提到的不足点之前,首先我们要搞清楚在真实项目开发过程中,哪些场景下是有必要做代码格式化的?其实在大多情况下,通过Git代码托管平台例如:gitee、github来进行代码管理时,我们只需要保证每一次push的代码以及在合并Pull Request(以下简称pr)时原分支的代码都是符合统一规范的代码即可。
在上篇文章中我们为仓库配置了webhook,并指定了在push操作后触发流程。为了达到上述需求,我们还需要在仓库webhooks的选择事件里勾选Pull Request。这样在仓库进行pr操作时也会触发格式化流程。
- 利用jsonpath、pr-file-diff节点提取需要进行格式化的文件路径信息
该如何避免在每一次流程中,prettier节点对整个项目进行格式化?参考prettier节点的使用说明可以知道,输入参数files中里可以具体指定需要格式化的文件,节点内部会循环查找对应的文件并格式化。如何才能拿到这些信息呢?不用着急,基于节点库中已有的jsonpath、pr-file-diff节点,现在可以非常方便的在push跟pr操作中提取到文件的变动信息。
复制下面的dsl,对之前代码格式化流程做一个升级。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
| name: prettier节点测试 description: prettier格式化前端代码
trigger: type: webhook param: - name: gitee_token type: SECRET exp: $.header.x-gitee-token - name: gitee_event type: STRING exp: $.header.x-gitee-event - name: project_name type: STRING exp: $.body.json.project.name - name: pr_url type: STRING exp: $.body.json.url - name: trigger_data type: STRING exp: $.body.json.commits - name: gitee_ref type: STRING exp: $.body.json.ref - name: source_branch type: STRING exp: $.body.json.source_branch - name: target_branch type: STRING exp: $.body.json.target_branch - name: commit_message type: STRING exp: $.body.json.commits[0].message - name: pr_repository_url type: STRING exp: $.body.json.source_repo.project.git_http_url - name: push_repository_url type: STRING exp: $.body.json.repository.git_http_url - name: project_full_name type: STRING exp: $.body.json.project.full_name - name: pr_user type: STRING exp: $.body.json.author.name - name: push_user type: STRING exp: $.body.json.pusher.name - name: pr_repository_html_url type: STRING exp: $.body.json.source_repo.project.html_url - name: push_repository_html_url type: STRING exp: $.body.json.repository.html_url - name: action_desc type: STRING exp: $.body.json.action_desc 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两个场景进行测试
等待流程执行成功,可以看见这次prettier节点只对有变化的文件进行了代码格式化。
在comyan分支下修改222.js文件
可以看见代码被推送到comyan分支下,但是此次操作并没有触发流程。
通过查看项目的webhook请求记录,可以发现这次请求状态是失败的。点击详情具体看看是什么原因造成的?
查看触发器参数值可以发现,流程only表达式中指定的gitee_ref跟此次webhook请求返回的gitee_ref不匹配,流程执行被限制。
流程执行pr分支
等待流程执行成功,刷新页面,可以发现在此次pr的提交里新增了一条refactor: auto format code记录。
之前在comyan分支下修改的文件在提交pr的时被自动格式化
经过上面3个场景的演示,你可能能够理解为什么在流程中我们对非主分支下push代码的操作做了条件限制。在通过新建pr对不同分支进行代码合并时,流程会对原分支代码格式化。加上这种机制,它可以减少流程被触发的次数。