An open API service indexing awesome lists of open source software.

https://github.com/reactnativecn/react-native-update-cli


https://github.com/reactnativecn/react-native-update-cli

Last synced: 15 days ago
JSON representation

Awesome Lists containing this project

README

          

# React Native Update CLI

[δΈ­ζ–‡ζ–‡ζ‘£](./README.zh-CN.md) | [Chinese Documentation](./README.zh-CN.md)

A unified React Native Update CLI that supports both traditional commands and modular architecture with custom publishing workflows.

## πŸš€ Features

- **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

## πŸ“¦ Installation

```bash
npm install react-native-update-cli
```

## 🎯 Quick Start

### Basic Usage

```bash
# 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
```

### Programmatic Usage

```typescript
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,
});
```

## πŸ”§ Creating Custom Modules

### 1. Define Module

```typescript
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');
},
};
```

### 2. Register Module

```typescript
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: {},
});
```

## πŸ”„ Workflow System

### Workflow Steps

Each workflow step contains:

- `name`: Step name
- `description`: Step description
- `execute`: Execution function
- `condition`: Optional condition function

### Conditional Execution

```typescript
{
name: 'conditional-step',
description: 'Only execute in production',
execute: async (context, previousResult) => {
// Execution logic
},
condition: (context) => {
return context.options.environment === 'production';
}
}
```

### Workflow Validation

```typescript
{
name: 'validated-workflow',
description: 'Workflow with validation',
steps: [...],
validate: (context) => {
if (!context.options.requiredParam) {
console.error('Required parameter missing');
return false;
}
return true;
}
}
```

## πŸ“‹ Built-in Modules

### Bundle Module (`bundle`)

- `bundle`: Bundle JavaScript code and optionally publish
- `diff`: Generate differences between two PPK files
- `hdiff`: Generate hdiff between two PPK files
- `diffFromApk`: Generate differences from APK files
- `hdiffFromApk`: Generate hdiff from APK files
- `hdiffFromApp`: Generate hdiff from APP files
- `diffFromIpa`: Generate differences from IPA files
- `hdiffFromIpa`: Generate hdiff from IPA files

### Version Module (`version`)

- `publish`: Publish new version
- `versions`: List all versions
- `update`: Update version information
- `updateVersionInfo`: Update version metadata

### App Module (`app`)

- `createApp`: Create new application
- `apps`: List all applications
- `selectApp`: Select application
- `deleteApp`: Delete application

### Package Module (`package`)

- `uploadIpa`: Upload IPA files (supports `--version` to override extracted version)
- `uploadApk`: Upload APK files (supports `--version` to override extracted version)
- `uploadAab`: Upload AAB files (converted to APK, supports `--version`, `--includeAllSplits`, `--splits`)
- `uploadApp`: Upload APP files (supports `--version` to override extracted version)
- `parseApp`: Parse APP file information
- `parseIpa`: Parse IPA file information
- `parseApk`: Parse APK file information
- `extractApk`: Extract a universal APK from an AAB (supports `--output`, `--includeAllSplits`, `--splits`)
- `packages`: List packages

### User Module (`user`)

- `login`: Login
- `logout`: Logout
- `me`: Show user information

## πŸ› οΈ CLI Provider API

### Core Functionality

```typescript
interface CLIProvider {
// Bundle
bundle(options: BundleOptions): Promise;

// Publish
publish(options: PublishOptions): Promise;

// Upload
upload(options: UploadOptions): Promise;

// Application management
getSelectedApp(
platform?: Platform,
): Promise<{ appId: string; platform: Platform }>;
listApps(platform?: Platform): Promise;
createApp(name: string, platform: Platform): Promise;

// Version management
listVersions(appId: string): Promise;
getVersion(appId: string, versionId: string): Promise;
updateVersion(
appId: string,
versionId: string,
updates: Partial,
): Promise;

// Package management
listPackages(appId: string, platform?: Platform): Promise;
getPackage(appId: string, packageId: string): Promise;

// Utility functions
getPlatform(platform?: Platform): Promise;
loadSession(): Promise;
saveToLocal(key: string, value: string): void;
question(prompt: string): Promise;

// Workflows
registerWorkflow(workflow: CustomWorkflow): void;
executeWorkflow(
workflowName: string,
context: CommandContext,
): Promise;
}
```

### Custom Commands

```typescript
// 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',
},
});
```

## πŸ”§ Configuration

### Environment Variables

```bash
# Set API endpoint
export PUSHY_REGISTRY=https://your-api-endpoint.com

# Set non-interactive mode
export NO_INTERACTIVE=true
```

### Configuration File

Create `update.json` file:

```json
{
"ios": {
"appId": "your-ios-app-id",
"appKey": "your-ios-app-key"
},
"android": {
"appId": "your-android-app-id",
"appKey": "your-android-app-key"
}
}
```

## 🚨 Important Notes

1. **Backward Compatibility**: The new modular CLI maintains compatibility with existing CLI
2. **Type Safety**: All APIs have complete TypeScript type definitions
3. **Error Handling**: All operations return standardized result formats
4. **Resource Cleanup**: Modules support cleanup functions to release resources
5. **Module Separation**: Functionality is logically separated into different modules for easy maintenance and extension

## 🀝 Contributing

Welcome to submit Issues and Pull Requests to improve this project!

## πŸš€ Provider API Usage Guide

Provider provides a concise programming interface suitable for integrating React Native Update CLI functionality in applications.

### πŸ“‹ Core API Methods

#### Core Business Functions

```typescript
// 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',
});
```

#### Application Management

```typescript
// Create application
await provider.createApp('MyApp', 'ios');

// List applications
await provider.listApps('ios');

// Get current application
const { appId, platform } = await provider.getSelectedApp('ios');
```

#### Version Management

```typescript
// List versions
await provider.listVersions('app123');

// Update version
await provider.updateVersion('app123', 'version456', {
name: 'v1.1.0',
description: 'New features',
});
```

#### Utility Functions

```typescript
// Get platform
const platform = await provider.getPlatform('ios');

// Load session
const session = await provider.loadSession();
```

### 🎯 Use Cases

#### 1. Automated Build Scripts

```typescript
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!');
}
```

#### 2. CI/CD Integration

```typescript
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;
}
```

#### 3. Application Management Service

```typescript
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 };
}
}
```

### ⚠️ Important Notes

1. **Error Handling**: All Provider methods return `CommandResult`, need to check the `success` field
2. **Type Safety**: Provider provides complete TypeScript type support
3. **Session Management**: Ensure login before use, can check via `loadSession()`
4. **Platform Support**: Supports `'ios' | 'android' | 'harmony'` three platforms

### πŸ”§ Advanced Features

#### Custom Workflows

```typescript
// 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: {} });
```

### πŸ“š Complete Example

```typescript
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');
```