δΈζζζ‘£ | Chinese Documentation
A unified React Native Update CLI that supports both traditional commands and modular architecture with custom publishing workflows.
- Unified CLI: Single
pushy
command for all functionality - Backward Compatibility: All existing commands work as before
- Modular Architecture: Split CLI functionality into independent modules
- Custom Workflows: Support for creating custom publishing workflows
- Extensibility: Users can import and register custom modules
- Type Safety: Complete TypeScript type support
npm install react-native-update-cli
# Use unified CLI npx pushy help # List all available commands and workflows npx pushy list # Execute built-in workflow npx pushy workflow setup-app # Execute custom workflow npx pushy workflow custom-publish
import { moduleManager, CLIProviderImpl } from 'react-native-update-cli'; // Get CLI provider const provider = moduleManager.getProvider(); // Execute bundling const bundleResult = await provider.bundle({ platform: 'ios', dev: false, sourcemap: true, }); // Publish version const publishResult = await provider.publish({ name: 'v1.2.3', description: 'Bug fixes and improvements', rollout: 100, });
import type { CLIModule, CommandDefinition, CustomWorkflow, } from 'react-native-update-cli'; export const myCustomModule: CLIModule = { name: 'my-custom', version: '1.0.0', commands: [ { name: 'custom-command', description: 'My custom command', handler: async (context) => { console.log('Executing custom command...'); return { success: true, data: { message: 'Custom command executed' }, }; }, options: { param: { hasValue: true, description: 'Custom parameter' }, }, }, ], workflows: [ { name: 'my-workflow', description: 'My custom workflow', steps: [ { name: 'step1', description: 'First step', execute: async (context, previousResult) => { console.log('Executing step 1...'); return { step1Completed: true }; }, }, { name: 'step2', description: 'Second step', execute: async (context, previousResult) => { console.log('Executing step 2...'); return { ...previousResult, step2Completed: true }; }, }, ], }, ], init: (provider) => { console.log('Custom module initialized'); }, cleanup: () => { console.log('Custom module cleanup'); }, };
import { moduleManager } from 'react-native-update-cli'; import { myCustomModule } from './my-custom-module'; // Register custom module moduleManager.registerModule(myCustomModule); // Execute custom command const result = await moduleManager.executeCommand('custom-command', { args: [], options: { param: 'value' }, }); // Execute custom workflow const workflowResult = await moduleManager.executeWorkflow('my-workflow', { args: [], options: {}, });
Each workflow step contains:
name
: Step namedescription
: Step descriptionexecute
: Execution functioncondition
: Optional condition function
{ name: 'conditional-step', description: 'Only execute in production', execute: async (context, previousResult) => { // Execution logic }, condition: (context) => { return context.options.environment === 'production'; } }
{ name: 'validated-workflow', description: 'Workflow with validation', steps: [...], validate: (context) => { if (!context.options.requiredParam) { console.error('Required parameter missing'); return false; } return true; } }
bundle
: Bundle JavaScript code and optionally publishdiff
: Generate differences between two PPK fileshdiff
: Generate hdiff between two PPK filesdiffFromApk
: Generate differences from APK fileshdiffFromApk
: Generate hdiff from APK fileshdiffFromApp
: Generate hdiff from APP filesdiffFromIpa
: Generate differences from IPA fileshdiffFromIpa
: Generate hdiff from IPA files
publish
: Publish new versionversions
: List all versionsupdate
: Update version informationupdateVersionInfo
: Update version metadata
createApp
: Create new applicationapps
: List all applicationsselectApp
: Select applicationdeleteApp
: Delete application
uploadIpa
: Upload IPA files (supports--version
to override extracted version)uploadApk
: Upload APK files (supports--version
to override extracted version)uploadApp
: Upload APP files (supports--version
to override extracted version)parseApp
: Parse APP file informationparseIpa
: Parse IPA file informationparseApk
: Parse APK file informationpackages
: List packages
login
: Loginlogout
: Logoutme
: Show user information
interface CLIProvider { // Bundle bundle(options: BundleOptions): Promise<CommandResult>; // Publish publish(options: PublishOptions): Promise<CommandResult>; // Upload upload(options: UploadOptions): Promise<CommandResult>; // Application management getSelectedApp( platform?: Platform, ): Promise<{ appId: string; platform: Platform }>; listApps(platform?: Platform): Promise<CommandResult>; createApp(name: string, platform: Platform): Promise<CommandResult>; // Version management listVersions(appId: string): Promise<CommandResult>; getVersion(appId: string, versionId: string): Promise<CommandResult>; updateVersion( appId: string, versionId: string, updates: Partial<Version>, ): Promise<CommandResult>; // Package management listPackages(appId: string, platform?: Platform): Promise<CommandResult>; getPackage(appId: string, packageId: string): Promise<CommandResult>; // Utility functions getPlatform(platform?: Platform): Promise<Platform>; loadSession(): Promise<Session>; saveToLocal(key: string, value: string): void; question(prompt: string): Promise<string>; // Workflows registerWorkflow(workflow: CustomWorkflow): void; executeWorkflow( workflowName: string, context: CommandContext, ): Promise<CommandResult>; }
// Execute custom bundle command const bundleResult = await moduleManager.executeCommand('custom-bundle', { args: [], options: { platform: 'android', validate: true, optimize: true, }, }); // Generate diff file const diffResult = await moduleManager.executeCommand('diff', { args: [], options: { origin: './build/v1.0.0.ppk', next: './build/v1.1.0.ppk', output: './build/diff.patch', }, }); // Generate diff from APK files const apkDiffResult = await moduleManager.executeCommand('diffFromApk', { args: [], options: { origin: './build/app-v1.0.0.apk', next: './build/app-v1.1.0.apk', output: './build/apk-diff.patch', }, });
# Set API endpoint export PUSHY_REGISTRY=https://your-api-endpoint.com # Set non-interactive mode export NO_INTERACTIVE=true
Create update.json
file:
{ "ios": { "appId": "your-ios-app-id", "appKey": "your-ios-app-key" }, "android": { "appId": "your-android-app-id", "appKey": "your-android-app-key" } }
- Backward Compatibility: The new modular CLI maintains compatibility with existing CLI
- Type Safety: All APIs have complete TypeScript type definitions
- Error Handling: All operations return standardized result formats
- Resource Cleanup: Modules support cleanup functions to release resources
- Module Separation: Functionality is logically separated into different modules for easy maintenance and extension
Welcome to submit Issues and Pull Requests to improve this project!
Provider provides a concise programming interface suitable for integrating React Native Update CLI functionality in applications.
// Bundle application await provider.bundle({ platform: 'ios', dev: false, sourcemap: true, }); // Publish version await provider.publish({ name: 'v1.0.0', description: 'Bug fixes', rollout: 100, }); // Upload file await provider.upload({ filePath: 'app.ipa', platform: 'ios', });
// Create application await provider.createApp('MyApp', 'ios'); // List applications await provider.listApps('ios'); // Get current application const { appId, platform } = await provider.getSelectedApp('ios');
// List versions await provider.listVersions('app123'); // Update version await provider.updateVersion('app123', 'version456', { name: 'v1.1.0', description: 'New features', });
// Get platform const platform = await provider.getPlatform('ios'); // Load session const session = await provider.loadSession();
import { moduleManager } from 'react-native-update-cli'; async function buildAndPublish() { const provider = moduleManager.getProvider(); // 1. Bundle const bundleResult = await provider.bundle({ platform: 'ios', dev: false, sourcemap: true, }); if (!bundleResult.success) { throw new Error(`Bundle failed: ${bundleResult.error}`); } // 2. Publish const publishResult = await provider.publish({ name: 'v1.2.3', description: 'Bug fixes and performance improvements', rollout: 100, }); if (!publishResult.success) { throw new Error(`Publish failed: ${publishResult.error}`); } console.log('Build and publish completed!'); }
async function ciBuild() { const provider = moduleManager.getProvider(); const result = await provider.bundle({ platform: process.env.PLATFORM as 'ios' | 'android', dev: process.env.NODE_ENV !== 'production', sourcemap: process.env.NODE_ENV === 'production', }); return result; }
class AppManagementService { private provider = moduleManager.getProvider(); async setupNewApp(name: string, platform: Platform) { // Create application const createResult = await this.provider.createApp(name, platform); if (createResult.success) { // Get application information const { appId } = await this.provider.getSelectedApp(platform); // List versions await this.provider.listVersions(appId); return { appId, success: true }; } return { success: false, error: createResult.error }; } }
- Error Handling: All Provider methods return
CommandResult
, need to check thesuccess
field - Type Safety: Provider provides complete TypeScript type support
- Session Management: Ensure login before use, can check via
loadSession()
- Platform Support: Supports
'ios' | 'android' | 'harmony'
three platforms
// Register custom workflow provider.registerWorkflow({ name: 'quick-release', description: 'Quick release process', steps: [ { name: 'bundle', execute: async () => { return await provider.bundle({ platform: 'ios', dev: false }); }, }, { name: 'publish', execute: async (context, bundleResult) => { if (!bundleResult.success) { throw new Error('Bundle failed, cannot publish'); } return await provider.publish({ name: 'auto-release', rollout: 50 }); }, }, ], }); // Execute workflow await provider.executeWorkflow('quick-release', { args: [], options: {} });
import { moduleManager } from 'react-native-update-cli'; class ReactNativeUpdateService { private provider = moduleManager.getProvider(); async initialize() { // Load session await this.provider.loadSession(); } async buildAndDeploy(platform: Platform, version: string) { try { // 1. Bundle const bundleResult = await this.provider.bundle({ platform, dev: false, sourcemap: true, }); if (!bundleResult.success) { throw new Error(`Bundle failed: ${bundleResult.error}`); } // 2. Publish const publishResult = await this.provider.publish({ name: version, description: `Release ${version}`, rollout: 100, }); if (!publishResult.success) { throw new Error(`Publish failed: ${publishResult.error}`); } return { success: true, data: publishResult.data }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } async getAppInfo(platform: Platform) { const { appId } = await this.provider.getSelectedApp(platform); const versions = await this.provider.listVersions(appId); return { appId, versions }; } } // Usage example const service = new ReactNativeUpdateService(); await service.initialize(); await service.buildAndDeploy('ios', 'v1.0.0');