UNPKG

appstore-cli

Version:

A command-line interface (CLI) to interact with the Apple App Store Connect API.

161 lines (148 loc) 6.24 kB
import yargs from 'yargs'; import { ConfigurationValidationMiddleware } from '../middleware/configuration-validation-middleware.js'; import fastlaneService from '../services/fastlane-service.js'; import { FastlaneServiceError } from '../services/fastlane-service.js'; import { safeLogger } from '../security/dataHandler.js'; import configurationService from '../services/configuration-service.js'; import migrateBuildAuthConfig from '../scripts/migrate-build-auth.js'; /** * CLI command for running the build process. */ export const buildRunCommand: yargs.CommandModule<{}, { clean?: boolean; 'provisioning-profile-path'?: string; 'certificate-path'?: string; 'certificate-password'?: string; 'use-automatic-signing'?: boolean; 'log-output'?: string; }> = { command: 'run', describe: 'Execute the build process', builder: (yargs) => { return yargs .option('clean', { alias: 'c', describe: 'Clean the build before building', type: 'boolean', default: false, }) .option('provisioning-profile-path', { describe: 'Path to the provisioning profile file (.mobileprovision)', type: 'string', }) .option('certificate-path', { describe: 'Path to the signing certificate file (.p12 or .pem)', type: 'string', }) .option('certificate-password', { describe: 'Password for the signing certificate (if encrypted)', type: 'string', }) .option('use-automatic-signing', { describe: 'Whether to use automatic code signing', type: 'boolean', }) .option('log-output', { alias: 'l', describe: 'Path to save the build log output to a file', type: 'string', }) .check((argv) => { // Validate certificate and provisioning profile paths for runtime overrides if (argv['provisioning-profile-path']) { if (!require('fs').existsSync(argv['provisioning-profile-path'])) { throw new Error(`Provisioning profile file not found: ${argv['provisioning-profile-path']}`); } if (!argv['provisioning-profile-path'].endsWith('.mobileprovision')) { throw new Error('Provisioning profile file must have .mobileprovision extension'); } } if (argv['certificate-path']) { if (!require('fs').existsSync(argv['certificate-path'])) { throw new Error(`Certificate file not found: ${argv['certificate-path']}`); } if (!argv['certificate-path'].endsWith('.p12') && !argv['certificate-path'].endsWith('.pem')) { throw new Error('Certificate file must have .p12 or .pem extension'); } } if (argv['certificate-path'] && argv['certificate-path'].endsWith('.p12') && argv['certificate-password'] === undefined) { throw new Error('Certificate password is required for .p12 certificate files'); } if (argv['use-automatic-signing'] && (argv['provisioning-profile-path'] || argv['certificate-path'])) { throw new Error('Cannot use automatic signing with manual provisioning profile or certificate paths'); } // Validate log output path if (argv['log-output']) { const path = require('path'); const dir = path.dirname(argv['log-output']); if (!require('fs').existsSync(dir)) { throw new Error(`Log output directory does not exist: ${dir}`); } } return true; }); }, handler: async (argv) => { try { // Check if we have an old build auth configuration and migrate it const authConfig = configurationService.loadAuthenticationConfiguration(); if (authConfig) { console.warn('⚠️ WARNING: Found deprecated build auth configuration.'); console.warn('Migrating to unified appstore-cli config...'); await migrateBuildAuthConfig(); console.warn('Migration completed. You can now remove the separate build auth configuration.'); console.warn(''); } // Check if we have certificate configuration let certConfig = configurationService.loadCertificateConfiguration() || {}; // Validate configurations using middleware const { buildConfig, authConfig: validatedAuthConfig } = ConfigurationValidationMiddleware.validateAllConfigurations(); if (!buildConfig) { console.error('Build configuration not found. Please run "appstore-cli build configure" first.'); process.exit(1); } // Merge runtime certificate overrides (do not persist) const runtimeCertOverrides: any = {}; if (argv['provisioning-profile-path']) { runtimeCertOverrides.provisioningProfilePath = argv['provisioning-profile-path']; } if (argv['certificate-path']) { runtimeCertOverrides.certificatePath = argv['certificate-path']; } if (argv['certificate-password']) { runtimeCertOverrides.certificatePassword = argv['certificate-password']; } if (argv['use-automatic-signing'] !== undefined) { runtimeCertOverrides.useAutomaticSigning = argv['use-automatic-signing']; } certConfig = { ...certConfig, ...runtimeCertOverrides }; // Execute the build console.log('Starting build process...'); const archivePath = await fastlaneService.executeBuild( buildConfig, validatedAuthConfig || {}, certConfig, argv.clean || false, argv['log-output'] ); // Output success message console.log(`Build completed successfully. Archive saved to: ${archivePath}`); } catch (error) { if (error instanceof FastlaneServiceError) { console.error(`Build failed: ${error.message}`); safeLogger.error('Build failed with FastlaneServiceError', { error: error.message, code: error.code }); } else { console.error(`Build failed: ${(error as Error).message}`); safeLogger.error('Build failed with unexpected error', { error: (error as Error).message }); } process.exit(1); } }, };