1
0
mirror of https://gitcode.com/github-mirrors/react-native-update-cli.git synced 2025-09-16 01:41:37 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee
Files
react-native-update-cli/example/workflows/custom-workflows.ts
波仔糕 e98bcf504f 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
2025-07-24 11:46:20 +08:00

583 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
];