1
0
mirror of https://gitcode.com/github-mirrors/react-native-update-cli.git synced 2025-09-16 09:41:38 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

cli modular refactor (#16)

* add logic to support SENTRY_PROPERTIES parameter

* remove update.json and meta.json files in ppk

* udpapte

* refactor modles

* update

* add package-module file

* update

* update readme file

* modifu cli.json file

* fix command issues

* improve version workflow logic

* udpate

* update

* update

* update

* udpate

* udpate

* add example

* update readme file

* udpate version

* change logic to use pushy command uniformly
This commit is contained in:
波仔糕
2025-07-24 11:46:20 +08:00
committed by GitHub
parent 4cb5f7fa4e
commit e98bcf504f
53 changed files with 10853 additions and 855 deletions

View File

@@ -0,0 +1,582 @@
import type {
CLIProvider,
CommandContext,
CustomWorkflow,
} from '../../src/types';
/**
* 自定义工作流集合
* 演示各种复杂的工作流场景
*/
/**
* 灰度发布工作流
*/
export const canaryDeploymentWorkflow: CustomWorkflow = {
name: 'canary-deployment',
description: '灰度发布工作流 - 逐步增加用户覆盖率',
steps: [
{
name: 'prepare-canary',
description: '准备灰度发布',
execute: async (context: CommandContext) => {
console.log('🔧 准备灰度发布环境...');
const { version, initialRollout = 5 } = context.options;
console.log(`📦 版本: ${version}`);
console.log(`📊 初始覆盖率: ${initialRollout}%`);
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
version,
currentRollout: initialRollout,
stage: 'prepared',
};
},
},
{
name: 'initial-deployment',
description: '初始小范围部署',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🚀 执行初始小范围部署...');
const { currentRollout } = previousResult;
console.log(`部署到 ${currentRollout}% 用户...`);
await new Promise((resolve) => setTimeout(resolve, 1500));
console.log('✅ 初始部署完成');
return {
...previousResult,
deploymentTime: new Date().toISOString(),
stage: 'initial-deployed',
};
},
},
{
name: 'monitor-metrics',
description: '监控关键指标',
execute: async (context: CommandContext, previousResult: any) => {
console.log('📊 监控关键指标...');
// 模拟监控数据
const metrics = {
crashRate: Math.random() * 0.01, // 0-1%
responseTime: 150 + Math.random() * 100, // 150-250ms
userSatisfaction: 85 + Math.random() * 10, // 85-95%
errorRate: Math.random() * 0.005, // 0-0.5%
};
console.log('📈 监控结果:');
console.log(` 崩溃率: ${(metrics.crashRate * 100).toFixed(3)}%`);
console.log(` 响应时间: ${metrics.responseTime.toFixed(1)}ms`);
console.log(` 用户满意度: ${metrics.userSatisfaction.toFixed(1)}%`);
console.log(` 错误率: ${(metrics.errorRate * 100).toFixed(3)}%`);
// 判断是否可以继续扩大范围
const canProceed =
metrics.crashRate < 0.005 &&
metrics.errorRate < 0.003 &&
metrics.userSatisfaction > 80;
console.log(`🔍 健康检查: ${canProceed ? '✅ 通过' : '❌ 未通过'}`);
return {
...previousResult,
metrics,
canProceed,
stage: 'monitored',
};
},
},
{
name: 'expand-rollout',
description: '扩大发布范围',
execute: async (context: CommandContext, previousResult: any) => {
const { canProceed, currentRollout } = previousResult;
if (!canProceed) {
console.log('⚠️ 指标不达标,停止扩大发布范围');
return {
...previousResult,
stage: 'rollout-stopped',
};
}
console.log('📈 扩大发布范围...');
const newRollout = Math.min(currentRollout * 2, 100);
console.log(`覆盖率从 ${currentRollout}% 扩大到 ${newRollout}%`);
await new Promise((resolve) => setTimeout(resolve, 1200));
return {
...previousResult,
currentRollout: newRollout,
stage: newRollout >= 100 ? 'fully-deployed' : 'expanded',
};
},
condition: (context: CommandContext) => {
// 只有在启用自动扩大的情况下才执行
return context.options.autoExpand !== false;
},
},
{
name: 'final-verification',
description: '最终验证',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🔍 执行最终验证...');
const { stage, currentRollout } = previousResult;
if (stage === 'rollout-stopped') {
console.log('❌ 灰度发布因指标不达标而停止');
return {
...previousResult,
finalStatus: 'failed',
reason: 'metrics-failed',
};
}
console.log('✅ 灰度发布验证完成');
console.log(`📊 最终覆盖率: ${currentRollout}%`);
return {
...previousResult,
finalStatus: 'success',
completedAt: new Date().toISOString(),
};
},
},
],
validate: (context: CommandContext) => {
if (!context.options.version) {
console.error('❌ 灰度发布必须指定版本号');
return false;
}
return true;
},
options: {
version: {
hasValue: true,
description: '发布版本号 (必需)',
},
initialRollout: {
hasValue: true,
default: 5,
description: '初始覆盖率百分比',
},
autoExpand: {
hasValue: false,
default: true,
description: '自动扩大发布范围',
},
},
};
/**
* 多环境发布工作流
*/
export const multiEnvironmentDeployWorkflow: CustomWorkflow = {
name: 'multi-env-deploy',
description: '多环境依次发布工作流',
steps: [
{
name: 'deploy-to-dev',
description: '部署到开发环境',
execute: async (context: CommandContext) => {
console.log('🔧 部署到开发环境...');
await new Promise((resolve) => setTimeout(resolve, 1000));
const devResult = {
environment: 'development',
deployTime: new Date().toISOString(),
success: true,
};
console.log('✅ 开发环境部署完成');
return { dev: devResult };
},
},
{
name: 'run-integration-tests',
description: '运行集成测试',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🧪 运行集成测试...');
const testSuites = ['API测试', '数据库测试', '第三方服务测试'];
const results = [];
for (const suite of testSuites) {
console.log(` 运行 ${suite}...`);
await new Promise((resolve) => setTimeout(resolve, 500));
const passed = Math.random() > 0.1; // 90% 通过率
results.push({ suite, passed });
console.log(` ${passed ? '✅' : '❌'} ${suite}`);
}
const allPassed = results.every((r) => r.passed);
console.log(
`🧪 集成测试结果: ${allPassed ? '✅ 全部通过' : '❌ 有失败项'}`,
);
return {
...previousResult,
integrationTests: { results, allPassed },
};
},
},
{
name: 'deploy-to-staging',
description: '部署到预发布环境',
execute: async (context: CommandContext, previousResult: any) => {
const { integrationTests } = previousResult;
if (!integrationTests.allPassed) {
throw new Error('集成测试未通过,无法部署到预发布环境');
}
console.log('🎭 部署到预发布环境...');
await new Promise((resolve) => setTimeout(resolve, 1500));
const stagingResult = {
environment: 'staging',
deployTime: new Date().toISOString(),
success: true,
};
console.log('✅ 预发布环境部署完成');
return {
...previousResult,
staging: stagingResult,
};
},
},
{
name: 'run-e2e-tests',
description: '运行端到端测试',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🎯 运行端到端测试...');
const e2eTests = [
'用户登录流程',
'核心业务流程',
'支付流程',
'数据同步',
];
const results = [];
for (const test of e2eTests) {
console.log(` 测试 ${test}...`);
await new Promise((resolve) => setTimeout(resolve, 800));
const passed = Math.random() > 0.05; // 95% 通过率
results.push({ test, passed });
console.log(` ${passed ? '✅' : '❌'} ${test}`);
}
const allPassed = results.every((r) => r.passed);
console.log(
`🎯 E2E测试结果: ${allPassed ? '✅ 全部通过' : '❌ 有失败项'}`,
);
return {
...previousResult,
e2eTests: { results, allPassed },
};
},
},
{
name: 'deploy-to-production',
description: '部署到生产环境',
execute: async (context: CommandContext, previousResult: any) => {
const { e2eTests } = previousResult;
if (!e2eTests.allPassed) {
console.log('⚠️ E2E测试未全部通过需要手动确认是否继续部署');
if (!context.options.forceProduction) {
throw new Error('E2E测试未通过使用 --force-production 强制部署');
}
}
console.log('🚀 部署到生产环境...');
// 生产部署需要更长时间
await new Promise((resolve) => setTimeout(resolve, 2000));
const productionResult = {
environment: 'production',
deployTime: new Date().toISOString(),
success: true,
version: context.options.version,
};
console.log('🎉 生产环境部署完成');
return {
...previousResult,
production: productionResult,
};
},
condition: (context: CommandContext) => {
// 只有在非跳过生产部署的情况下才执行
return !context.options.skipProduction;
},
},
{
name: 'post-deployment-verification',
description: '部署后验证',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🔍 执行部署后验证...');
const verifications = [
'健康检查',
'关键接口测试',
'监控数据验证',
'用户访问验证',
];
for (const verification of verifications) {
console.log(` ${verification}...`);
await new Promise((resolve) => setTimeout(resolve, 300));
console.log(`${verification} 通过`);
}
console.log('✅ 部署后验证完成');
return {
...previousResult,
postDeploymentVerification: {
completed: true,
verifiedAt: new Date().toISOString(),
},
};
},
},
],
validate: (context: CommandContext) => {
if (!context.options.version) {
console.error('❌ 多环境部署必须指定版本号');
return false;
}
return true;
},
options: {
version: {
hasValue: true,
description: '发布版本号 (必需)',
},
skipProduction: {
hasValue: false,
default: false,
description: '跳过生产环境部署',
},
forceProduction: {
hasValue: false,
default: false,
description: '强制部署到生产环境(即使测试未全部通过)',
},
},
};
/**
* 回滚工作流
*/
export const rollbackWorkflow: CustomWorkflow = {
name: 'rollback-workflow',
description: '应用回滚工作流',
steps: [
{
name: 'validate-target-version',
description: '验证目标版本',
execute: async (context: CommandContext) => {
console.log('🔍 验证目标回滚版本...');
const { targetVersion } = context.options;
if (!targetVersion) {
throw new Error('必须指定目标回滚版本');
}
// 模拟版本验证
console.log(`验证版本 ${targetVersion} 是否存在...`);
await new Promise((resolve) => setTimeout(resolve, 800));
const versionExists = true; // 模拟版本存在
if (!versionExists) {
throw new Error(`版本 ${targetVersion} 不存在`);
}
console.log(`✅ 版本 ${targetVersion} 验证通过`);
return {
targetVersion,
validated: true,
};
},
},
{
name: 'backup-current-state',
description: '备份当前状态',
execute: async (context: CommandContext, previousResult: any) => {
console.log('💾 备份当前应用状态...');
const backup = {
backupId: `backup-${Date.now()}`,
timestamp: new Date().toISOString(),
currentVersion: 'current-version', // 在实际应用中获取当前版本
configSnapshot: 'config-data', // 在实际应用中获取配置快照
};
await new Promise((resolve) => setTimeout(resolve, 1500));
console.log(`✅ 状态备份完成备份ID: ${backup.backupId}`);
return {
...previousResult,
backup,
};
},
},
{
name: 'execute-rollback',
description: '执行回滚',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🔄 执行回滚操作...');
const { targetVersion } = previousResult;
console.log(`回滚到版本: ${targetVersion}`);
// 模拟回滚过程
const rollbackSteps = [
'停止当前服务',
'切换到目标版本',
'更新配置',
'重启服务',
];
for (const step of rollbackSteps) {
console.log(` ${step}...`);
await new Promise((resolve) => setTimeout(resolve, 600));
console.log(`${step} 完成`);
}
console.log('🎉 回滚执行完成');
return {
...previousResult,
rollbackCompleted: true,
rollbackTime: new Date().toISOString(),
};
},
},
{
name: 'verify-rollback',
description: '验证回滚结果',
execute: async (context: CommandContext, previousResult: any) => {
console.log('🔍 验证回滚结果...');
const verificationChecks = [
'服务可用性检查',
'功能完整性检查',
'性能基线检查',
'数据一致性检查',
];
const results = [];
for (const check of verificationChecks) {
console.log(` ${check}...`);
await new Promise((resolve) => setTimeout(resolve, 400));
const passed = Math.random() > 0.05; // 95% 通过率
results.push({ check, passed });
console.log(` ${passed ? '✅' : '❌'} ${check}`);
}
const allPassed = results.every((r) => r.passed);
if (!allPassed) {
console.log('⚠️ 部分验证未通过,可能需要进一步检查');
} else {
console.log('✅ 回滚验证全部通过');
}
return {
...previousResult,
verification: { results, allPassed },
};
},
},
{
name: 'notify-stakeholders',
description: '通知相关人员',
execute: async (context: CommandContext, previousResult: any) => {
console.log('📧 通知相关人员...');
const { targetVersion, verification } = previousResult;
const notification = {
type: 'rollback-completed',
targetVersion,
success: verification.allPassed,
timestamp: new Date().toISOString(),
notifiedStakeholders: [
'开发团队',
'运维团队',
'产品团队',
'测试团队',
],
};
console.log('📬 发送通知给:');
notification.notifiedStakeholders.forEach((stakeholder) => {
console.log(` - ${stakeholder}`);
});
await new Promise((resolve) => setTimeout(resolve, 500));
console.log('✅ 通知发送完成');
return {
...previousResult,
notification,
};
},
},
],
validate: (context: CommandContext) => {
if (!context.options.targetVersion) {
console.error('❌ 回滚操作必须指定目标版本');
return false;
}
return true;
},
options: {
targetVersion: {
hasValue: true,
description: '目标回滚版本 (必需)',
},
skipVerification: {
hasValue: false,
default: false,
description: '跳过回滚后验证',
},
},
};
/**
* 导出所有工作流
*/
export const customWorkflows = [
canaryDeploymentWorkflow,
multiEnvironmentDeployWorkflow,
rollbackWorkflow,
];

File diff suppressed because it is too large Load Diff