UNPKG

@hughcube/dev-toolkit

Version:

一套完整的开发工具集,包含小程序版本管理、代码上传、开发配置等功能

323 lines (278 loc) 12.2 kB
/** * 支付宝小程序上传工具 */ const fs = require('fs') const path = require('path') const os = require('os') const { execSync } = require('child_process') class MpAlipayUploader { constructor() { this.parseArgs() this.validateConfig() // 构建 minidev 命令路径,使用当前 Node.js 可执行文件路径 this.minidevPath = `"${process.execPath}" "${path.join(process.cwd(), 'node_modules/minidev/bin/minidev.js')}"` } /** * 解析命令行参数 */ parseArgs() { const args = process.argv.slice(2) if (args.includes('--help') || args.includes('-h')) { this.showHelp() process.exit(0) } // CLI 参数解析 const getArgValue = (flags) => { for (const flag of flags) { const index = args.findIndex(arg => arg === flag) if (index !== -1 && args[index + 1]) { return args[index + 1] } } return null } // 获取命令行参数 this.appId = getArgValue(['--app-id', '-a']) || null this.distDir = getArgValue(['--dist-dir', '-d']) || null this.version = getArgValue(['--version', '-v']) || null this.minidevConfig = getArgValue(['--config', '-c']) || null this.versionDescribe = getArgValue(['--version-describe']) || null // 确保版本号有 v 前缀 if (this.version && !this.version.startsWith('v') && !this.version.startsWith('V')) { this.version = 'v' + this.version } // 设置默认版本描述 if (!this.versionDescribe && this.version) { this.versionDescribe = `版本 ${this.version} 自动上传` } // minidevConfig默认路径(仅在未设置时) if (!this.minidevConfig) { this.minidevConfig = path.join(os.homedir(), '.minidev', 'config.json') } } /** * 显示帮助信息 */ showHelp() { console.log(` 支付宝小程序上传工具 使用方法: hctoolkit-mp-alipay-uploader --app-id <AppID> --dist-dir <目录> --version <版本> --config <配置文件> 参数: --app-id, -a 小程序 APPID (必填) --dist-dir, -d 构建产物目录 (必填) --version, -v 版本号 (必填,格式: vx.x.x) --config, -c minidev 配置文件路径 (必填) --version-describe 版本描述 (可选) --help, -h 显示帮助信息 示例: hctoolkit-mp-alipay-uploader \\ --app-id 2021005160675311 \\ --dist-dir ./dist/build/mp-alipay \\ --version v1.2.3 \\ --config ./minidev-config.json \\ --version-describe "新版本发布" 前置条件: 1. 安装依赖: npm install minidev 2. 准备 minidev 配置文件,包含私钥和工具ID 3. 确保构建产物目录存在 4. 支持跨平台运行 (Windows, macOS, Linux) 配置文件格式 (minidev-config.json): { "alipay": { "authentication": { "privateKey": "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----", "toolId": "your-tool-id" } } } `) } /** * 验证配置 */ validateConfig() { const errors = [] if (!this.appId) { errors.push('❌ 缺少小程序 APPID') errors.push(' 请使用 --app-id 参数') } if (!this.distDir) { errors.push('❌ 缺少构建产物目录') errors.push(' 请使用 --dist-dir 参数') } else if (!fs.existsSync(this.distDir)) { errors.push(`❌ 构建产物目录不存在: ${this.distDir}`) } if (!this.version) { errors.push('❌ 缺少版本号') errors.push(' 请使用 --version 参数') } else { // 验证版本号格式(去掉v前缀后验证) const versionWithoutV = this.version.replace(/^v/i, '') if (!/^\d+\.\d+\.\d+$/.test(versionWithoutV)) { errors.push(`❌ 版本号格式错误: ${this.version},应为 vx.x.x 格式`) } } if (!this.minidevConfig) { errors.push('❌ 缺少 minidev 配置文件路径') errors.push(' 请使用 --config 参数') } else if (!fs.existsSync(this.minidevConfig)) { errors.push(`❌ minidev 配置文件不存在: ${this.minidevConfig}`) } if (errors.length > 0) { console.error('\n配置验证失败:') errors.forEach(err => console.error(err)) console.error('\n请确保提供了所有必需参数。使用 --help 查看详细说明。\n') process.exit(1) } } /** * 上传小程序代码 * @returns {Promise<boolean>} */ async upload() { console.log('\n📤 开始上传小程序代码...') console.log(` 版本号: ${this.version}`) console.log(` 版本描述: ${this.versionDescribe}`) console.log(` 项目路径: ${this.distDir}`) try { // 注意:minidev 需要不带 v 的版本号 const versionWithoutV = this.version.replace(/^v/i, '') const uploadCmd = `${this.minidevPath} upload --identity-key-path "${this.minidevConfig}" --app-id "${this.appId}" --project "${this.distDir}" --version "${versionWithoutV}" --version-description "${this.versionDescribe}"` console.log('执行命令:', uploadCmd) execSync(uploadCmd, { stdio: 'inherit' }) console.log('✅ 代码上传成功') return true } catch (error) { console.error('❌ 代码上传失败:', error.message) return false } } /** * 查询版本状态 * @returns {Promise<{found: boolean, version: string, status: string}>} */ async queryVersionStatus() { console.log('\n🔍 查询版本状态...') try { // 注意:minidev 需要不带 v 的版本号 const versionWithoutV = this.version.replace(/^v/i, '') let pageNum = 1 let found = false let versionInfo = null console.log(` 正在查找版本 ${versionWithoutV}...`) // 分页查询,直到找到版本或没有更多数据 while (!found) { const queryCmd = `${this.minidevPath} app get-uploaded-version-list --app-id "${this.appId}" --identity-key-path "${this.minidevConfig}" --page-num ${pageNum} --machine-output` console.log(` 查询第 ${pageNum} 页...`) let output try { output = execSync(queryCmd, { encoding: 'utf8' }) } catch (cmdError) { console.error(` 查询第 ${pageNum} 页失败:`, cmdError.message) break } // 解析JSON输出 let versionList = [] try { const parsed = JSON.parse(output.trim()) versionList = Array.isArray(parsed) ? parsed : [] } catch (parseError) { console.error(` 第 ${pageNum} 页数据解析失败:`, parseError.message) console.error(' 原始输出:', output) break } console.log(` 第 ${pageNum} 页找到 ${versionList.length} 个版本`) // 如果没有数据,说明已经查完了 if (versionList.length === 0) { console.log(' 已查询完所有页面') break } // 查找目标版本 for (const version of versionList) { if (version.appVersion === versionWithoutV) { found = true versionInfo = version console.log(` ✅ 在第 ${pageNum} 页找到版本 ${versionWithoutV}`) break } } if (pageNum > 20) { console.log(' 已查询20页,停止查询') break } pageNum++; } if (found && versionInfo) { return { found: true, version: versionWithoutV, status: versionInfo.versionStatus, createTime: versionInfo.createTime, description: versionInfo.versionDescription, canRelease: versionInfo.canRelease } } else { console.error(`\n❌ 未找到版本 ${versionWithoutV}`) return { found: false, version: versionWithoutV, status: null } } } catch (error) { console.error('❌ 版本查询失败:', error.message) return { found: false, version: this.version.replace(/^v/i, ''), status: null, error: error.message } } } /** * 执行上传流程 */ async run() { console.log('🚀 支付宝小程序上传工具') console.log('============================') console.log('🖥️ 运行平台:', process.platform) console.log('📱 小程序 APPID:', this.appId) console.log('📌 版本号:', this.version) console.log('📝 版本描述:', this.versionDescribe) console.log('🔧 配置文件:', this.minidevConfig) console.log('🛠 Minidev路径:', this.minidevPath) console.log('📂 输出目录:', this.distDir) console.log('============================\n') try { // 上传代码 const uploadSuccess = await this.upload() if (!uploadSuccess) { console.log('\n🔗 请手动登录支付宝开放平台:') console.log(' https://open.alipay.com/dev/mini-games') console.error('\n❌ 上传失败,流程中止') process.exit(1) } // 查询验证上传结果 console.log('\n🔍 正在验证上传结果...') console.log(' 等待系统处理(3秒)...') await new Promise(resolve => setTimeout(resolve, 3000)) const queryResult = await this.queryVersionStatus() if (!queryResult.found) { console.warn(`\n⚠️ 版本验证异常:未能在平台上找到版本 ${this.version.replace(/^v/i, '')}`) if (queryResult.error) { console.warn(` 错误信息: ${queryResult.error}`) } console.warn(' 建议手动登录平台确认上传状态') console.log(`🔗 https://open.alipay.com/develop/mini/sub/dev-manage?appId=${this.appId}&bundleId=com.alipay.alipaywallet`) console.error('\n❌ 上传验证失败,流程中止') process.exit(1) } console.log(`\n✅ 版本验证成功!版本 ${queryResult.version} 已成功上传`) console.log(`📋 当前状态: ${queryResult.status}`) if (queryResult.createTime) console.log(`📅 创建时间: ${queryResult.createTime}`) if (queryResult.description) console.log(`📝 版本描述: ${queryResult.description}`) console.log('\n✅ 代码上传流程完成!') console.log('============================') console.log('📱 请登录支付宝小程序管理后台完成审核提交') console.log('🔗 https://open.alipay.com/mini/dev/list') console.log(`🔗 https://open.alipay.com/develop/mini/sub/dev-manage?appId=${this.appId}&bundleId=com.alipay.alipaywallet`) console.log('💡 由于审核需要上传版本截图,请在平台上手动完成最后的审核提交步骤') } catch (error) { console.error('❌ 执行失败:', error) process.exit(1) } } } module.exports = MpAlipayUploader;