场景
公司内部使用的 RN
打包,由于改成了 monorepo
的形式,导致在线打包无法使用,故开发了一个 publish
脚本。
需求
- 如果为生产环境,判断本地分支是不是处于
master
,如果为开发环境,判断本地分支是不是处理feature
- 判断本地工作区及暂存区是否
clean
- 判断本地和远程分支是否为同一节点
- 全部通过后执行打包发布命令
代码
我写的版本
const shell = require('shelljs')
const { select, checkbox, input } = require('@inquirer/prompts')
shell.config.silent = true
const errorlog = val => {
console.log('\033[31m' + val + '\033[0m')
}
;(async () => {
const env = await select({
message: '请选择发布环境',
choices: [
{ name: '测试环境', value: 'dev' },
{ name: '生产环境', value: 'pro' }
]
})
const apps = await checkbox({
message: '请选择要发布的应用',
choices: [
{
name: 'xxxxx',
value: 'xxxxx'
},
{
name: 'vvvvv',
value: 'vvvvv'
}
]
})
const descs = []
for (const app of apps) {
const res = await input({ message: `请输入${app}发布的内容` })
descs.push(res)
}
const p = apps.join(' ')
const d = descs.join(' ')
const stdout = shell.exec('git rev-parse --abbrev-ref HEAD').stdout.trim()
if (stdout !== 'master') {
return errorlog('你必须在 master 分支才能执行发布命令')
}
const status = shell.exec('git diff').stdout.trim()
if (status.length !== 0) {
return errorlog('你工作区有未 commit 的代码,请提交后再发布')
}
const cached = shell.exec('git diff --cached').stdout.trim()
if (cached.length !== 0) {
return errorlog('你暂存区有未 commit 的代码,请提交后再发布')
}
const lastCommit = shell.exec('git rev-parse master').stdout.trim()
const originLastCommit = shell.exec('git rev-parse origin/master').stdout.trim()
if (lastCommit !== originLastCommit) {
return errorlog('你的本地代码和远程代码不一致,请合并/推送远程分支')
}
shell.exec('发布命令')
})()
chatGPT 改写的第一版
将源数据喂给 chatGPT
,它把 return errorLog('xxx')
改造成了,try catch throw
的形式。(看起来好像确实不错)
try {
// 前半部分一致...
const p = apps.join(' ');
const d = descriptions.join(' ');
const stdout = shell.exec('git rev-parse --abbrev-ref HEAD', { silent: true }).stdout.trim();
if (stdout !== 'master') {
throw new Error('你必须在 master 分支才能执行发布命令');
}
const status = shell.exec('git diff', { silent: true }).stdout.trim();
if (status.length !== 0) {
throw new Error('你工作区有未 commit 的代码,请提交后再发布');
}
const cached = shell.exec('git diff --cached', { silent: true }).stdout.trim();
if (cached.length !== 0) {
throw new Error('你暂存区有未 commit 的代码,请提交后再发布');
}
const lastCommit = shell.exec('git rev-parse master', { silent: true }).stdout.trim();
const originLastCommit = shell.exec('git rev-parse origin/master', { silent: true }).stdout.trim();
if (lastCommit !== originLastCommit) {
throw new Error('你的本地代码和远程代码不一致,请合并/推送远程分支');
}
shell.exec('发布命令');
} catch (err) {
errorlog(err.message);
}
使用拦截器模式进行改写
直接帮我改成了拦截器模式,太强了
class Interceptor {
constructor() {
this.interceptors = [];
}
use(interceptor) {
this.interceptors.push(interceptor);
return this;
}
async execute(context) {
for (const interceptor of this.interceptors) {
await interceptor(context);
if (context.abort) {
break;
}
}
}
}
const interceptor = new Interceptor();
interceptor.use(async (context) => {
const stdout = shell.exec('git rev-parse --abbrev-ref HEAD', { silent: true }).stdout.trim();
if (stdout !== 'master') {
throw new Error('你必须在 master 分支才能执行发布命令');
}
});
interceptor.use(async (context) => {
const status = shell.exec('git diff', { silent: true }).stdout.trim();
if (status.length !== 0) {
throw new Error('你工作区有未 commit 的代码,请提交后再发布');
}
});
interceptor.use(async (context) => {
const cached = shell.exec('git diff --cached', { silent: true }).stdout.trim();
if (cached.length !== 0) {
throw new Error('你暂存区有未 commit 的代码,请提交后再发布');
}
});
interceptor.use(async (context) => {
const lastCommit = shell.exec('git rev-parse master', { silent: true }).stdout.trim();
const originLastCommit = shell.exec('git rev-parse origin/master', { silent: true }).stdout.trim();
if (lastCommit !== originLastCommit) {
throw new Error('你的本地代码和远程代码不一致,请合并/推送远程分支');
}
});
try {
// 前半部分一致...
const p = apps.join(' ');
const d = descriptions.join(' ');
context.env = env;
context.p = p;
context.d = d;
await interceptor.execute(context);
shell.exec(`zmas mono_publish ${context.env} -p ${context.p} -d ${context.d}`);
} catch (err) {
console.log('\033[31m' + err.message + '\033[0m');
}
生产环境和测试环境会有相同和不同的拦截者
建议我增加一个公共拦截器、生产环境的拦截器、测试环境的拦截器
/ 公共拦截器
const commonInterceptor = new Interceptor();
commonInterceptor.use(async (context) => {
// 添加公共的拦截逻辑
});
// 生产环境拦截器
const productionInterceptor = new Interceptor();
productionInterceptor.use(async (context) => {
// 添加生产环境的特定拦截逻辑
});
// 测试环境拦截器
const testInterceptor = new Interceptor();
testInterceptor.use(async (context) => {
// 添加测试环境的特定拦截逻辑
});
// 然后业务层改成这样
try {
// ...
let interceptor;
if (env === 'pro') {
interceptor = commonInterceptor.use(productionInterceptor);
} else if (env === 'dev') {
interceptor = commonInterceptor.use(testInterceptor);
}
await interceptor.execute(context);
// ...
} catch {
// ...
}
使用责任链模式帮我改写
class Handler {
constructor() {
this.nextHandler = null;
}
setNext(handler) {
this.nextHandler = handler;
return handler;
}
async handleRequest(context) {
throw new Error('handleRequest method must be implemented');
}
}
class BranchHandler extends Handler {
async handleRequest(context) {
const stdout = shell.exec('git rev-parse --abbrev-ref HEAD', { silent: true }).stdout.trim();
if (stdout !== 'master') {
throw new Error('你必须在 master 分支才能执行发布命令');
}
if (this.nextHandler) {
await this.nextHandler.handleRequest(context);
}
}
}
class StatusHandler extends Handler {
async handleRequest(context) {
const status = shell.exec('git diff', { silent: true }).stdout.trim();
if (status.length !== 0) {
throw new Error('你工作区有未 commit 的代码,请提交后再发布');
}
if (this.nextHandler) {
await this.nextHandler.handleRequest(context);
}
}
}
class CachedHandler extends Handler {
async handleRequest(context) {
const cached = shell.exec('git diff --cached', { silent: true }).stdout.trim();
if (cached.length !== 0) {
throw new Error('你暂存区有未 commit 的代码,请提交后再发布');
}
if (this.nextHandler) {
await this.nextHandler.handleRequest(context);
}
}
}
class CommitHandler extends Handler {
async handleRequest(context) {
const lastCommit = shell.exec('git rev-parse master', { silent: true }).stdout.trim();
const originLastCommit = shell.exec('git rev-parse origin/master', { silent: true }).stdout.trim();
if (lastCommit !== originLastCommit) {
throw new Error('你的本地代码和远程代码不一致,请合并/推送远程分支');
}
if (this.nextHandler) {
await this.nextHandler.handleRequest(context);
}
}
}
拦截器和责任链哪种模式更好一些?
拦截器模式和责任链模式都是常见的设计模式,用于处理请求或执行一系列操作。它们在不同的场景中可以有不同的应用。
拦截器模式适用于需要在请求处理前后添加额外逻辑的情况。它提供了一种简单的方式来拦截和修改请求,可以对请求进行前置处理、后置处理或中间处理。拦截器模式通常用于对请求进行处理、记录日志、验证权限等方面。它的优点是结构简单、易于理解和实现。
责任链模式适用于需要按照特定顺序处理请求,并且每个处理程序有机会处理请求或将其传递给下一个处理程序的情况。责任链模式允许你将多个处理程序组成一个链,每个处理程序负责处理请求的一部分,并将请求传递给链中的下一个处理程序。责任链模式通常用于请求的多个处理阶段、动态决定请求的处理方式等方面。它的优点是灵活性高、可扩展性强,并且可以动态地调整和组合处理程序。
在选择使用哪种模式时,你可以考虑以下因素:
- 处理逻辑的复杂性:如果处理逻辑相对简单,只需要在请求前后添加一些操作,那么拦截器模式可能更合适。如果处理逻辑比较复杂,需要按照特定顺序处理请求,并且可能存在多个处理阶段,那么责任链模式可能更适合。
- 扩展性和灵活性:如果你希望能够方便地添加、移除或调整处理程序,以及动态地组合处理程序,那么责任链模式的灵活性更好。如果只是简单地添加一些额外逻辑,拦截器模式可能更简单和直观。
- 可读性和维护性:拦截器模式通常更直观和易于理解,因为逻辑在一个地方集中。责任链模式可能会将逻辑分散在多个处理程序中,可能会增加代码的复杂性和理解的难度。
总而言之,拦截器模式和责任链模式都有各自的优点和适用场景。选择哪种模式取决于你的需求和设计上的考虑。在简单的场景中,拦截器模式可能更简单和直接。在复杂的场景中,需要按照特定顺序处理请求或动态地调整处理程序时,责任链模式提供了更大的灵活性和可扩展性。
总结
chatGPT 太强了,我是渣渣。
它可能没有办法写出逻辑正确的代码,但是如果把逻辑正确的代码优化一下,水平确实高的难以想象。