/** * Factiii Pipeline Plugin * * The default pipeline plugin for Factiii Stack. * Uses GitHub Actions for CI/CD with thin workflows that SSH to servers * and call the Factiii CLI to do the actual work. * * ============================================================ * PLUGIN STRUCTURE STANDARD * ============================================================ * * This plugin follows a standardized structure for clarity and maintainability: * * **scanfix/** - Scan/fix operations organized by concern * - Each file exports an array of Fix[] objects * - Files group related fixes together (config, github-cli, workflows, secrets) * - All fixes are combined in the main plugin class * * **utils/** - Utility methods * - detection.ts - Config detection methods (package manager, Node.js version, etc.) * - workflows.ts - Workflow generation and triggering * * **index.ts** - Main plugin class * - Static metadata (id, name, category, version) * - shouldLoad() - Determines if plugin should load * - canReach() - Determines how to reach each stage (critical routing method) * - Imports and combines all scanfix arrays * - Imports and uses utility methods * - Core pipeline logic: deployStage(), runLocalDeploy() * - Maintains public API compatibility * * **Key Differences from Server Plugins:** * - Environment-specific files (staging.ts, prod.ts) are in plugin root - standard pattern * - Core routing logic stays in index.ts - canReach() and deployStage() are the main entry points * - Utils folder for static helpers - Detection and workflow generation are utilities, not core logic * - scanfix organized by concern, not environment - Fixes are grouped by what they check (config, workflows, secrets) * * **When each scanfix file is used:** * - config.ts: When checking/generating stack.yml * - github-cli.ts: When checking GitHub CLI installation (dev) * - workflows.ts: When checking/generating GitHub workflows (dev) * - secrets.ts: When checking Ansible Vault secrets (vault unlock, SSH key extraction) * ============================================================ */ import type { FactiiiConfig, Stage, Reachability, Fix, DeployResult, DeployOptions, EnvironmentConfig, PluginCommand, CommandResult } from '../../../types/index.js'; import * as detectionUtils from './utils/detection.js'; declare class FactiiiPipeline { static readonly id = "factiii"; static readonly name = "Factiii Pipeline"; static readonly category: 'pipeline'; static readonly version = "1.0.0"; static readonly requiredEnvVars: string[]; static readonly configSchema: Record; static readonly autoConfigSchema: Record; /** * Determine if this plugin should be loaded for this project * Pipeline plugin always loads - it's the default CI/CD system */ static shouldLoad(_rootDir: string, _config: FactiiiConfig): Promise; /** * Whether this environment requires the full repo cloned on the server */ static requiresFullRepo(environment: string): boolean; /** * Check if this pipeline can reach a specific stage * * ============================================================ * PIPELINE AUTHORS: This method controls stage reachability * ============================================================ * * Return values: * { reachable: true, via: 'local' } - Run fixes on this machine * { reachable: false, reason: '...' } - Cannot reach, show error * * Dev-direct model: all execution happens on the dev machine. Staging/prod * fixes that need server state reach through an SSH tunnel opened by * runStageChain (see utils/ssh-tunnel.ts). canReach() never returns * via: 'ssh' — there is no remote stack CLI to invoke. * * For the Factiii pipeline: * - dev: always local * - staging/prod: * - If SSH key exists at ~/.ssh/{stage}_deploy_key → local (tunnel via runStageChain) * - Otherwise → not reachable (guide user to set up SSH keys) * ============================================================ */ static canReach(stage: Stage, config: FactiiiConfig): Reachability; static readonly fixes: Fix[]; /** * Get the env file for a stage * - dev: .env * - staging: .env.staging * - prod: .env.prod */ static getEnvFile(stage: Stage): string; /** * Load environment variables from a file */ static loadEnvFile(rootDir: string, envFile: string): Record; /** * Find the directory containing Prisma (for db commands) * Checks common monorepo locations */ static findDbDir(rootDir: string): string; /** * Run a database command - uses docker exec for staging/prod * @param command - The command to run (e.g., 'prisma migrate status' or 'pnpm db:seed') * @param useNpx - Whether to prefix with npx (false for pnpm commands) */ static runDbCommand(command: string, stage: Stage, config: FactiiiConfig, rootDir: string, useNpx?: boolean): void; /** * Change the Ansible Vault password for the configured vault file. * * This runs locally on the dev machine and uses: * ansible-vault rekey --vault-password-file --new-vault-password-file * * It then overwrites the configured vault_password_file with the new password * so future commands use the updated password. */ static changeVaultPassword(config: FactiiiConfig, rootDir: string): Promise; static readonly commands: PluginCommand[]; /** * Resolve SSH target (host, user, key) for a stage. * Shared by localOnly commands that manually SSH to run remote commands. */ static resolveSSHTarget(stage: Stage, config: FactiiiConfig): Promise<{ success: true; host: string; user: string; keyPath: string; } | { success: false; error: string; }>; /** * Run a command on a remote server via SSH with a login shell. * Uses bash -lc to ensure PATH includes docker/colima/etc. */ static sshExecCommand(keyPath: string, user: string, host: string, remoteCmd: string, options?: { interactive?: boolean; }): { stdout: string; stderr: string; status: number | null; }; /** * Auto-detect pipeline configuration */ static detectConfig(rootDir: string): Promise; /** * Detect package manager */ static detectPackageManager(rootDir: string): string; /** * Detect Node.js version from package.json */ static detectNodeVersion(rootDir: string): string | null; /** * Detect pnpm version from package.json */ static detectPnpmVersion(rootDir: string): string | null; /** * Find Dockerfile */ static findDockerfile(rootDir: string): string | null; /** * Generate GitHub workflow files in the target repository */ static generateWorkflows(rootDir: string): Promise; /** * Build staging Docker image (linux/arm64) on staging server */ static buildStagingImage(config: FactiiiConfig, envConfig: EnvironmentConfig): Promise; /** * Build production Docker image (linux/amd64) on staging server and push to ECR */ static buildProductionImage(config: FactiiiConfig, stagingConfig: EnvironmentConfig): Promise; /** * Build production Docker image locally on the prod server itself and push to ECR. * Used when deploying directly on the prod server (FACTIII_ON_SERVER=true). */ static buildProductionImageLocally(config: FactiiiConfig): Promise; /** * Build prod image on staging and stream it directly to prod via dev relay. * Selected when prod has no registry/AWS configured but a staging server exists. */ static buildAndShipProdImage(config: FactiiiConfig, stagingConfig: EnvironmentConfig, prodConfig: EnvironmentConfig): Promise; /** * Run the prod-side `docker compose up` for the registry-less flow. * Pairs with buildAndShipProdImage — image is already loaded on prod. */ static deployProdPiped(config: FactiiiConfig, prodConfig: EnvironmentConfig): Promise; private _config; constructor(config: FactiiiConfig); /** * Deploy to a stage - handles routing based on canReach() * * This is the main entry point for deployments. Checks canReach() to determine: * - 'local': Execute deployment directly (dev stage, or when running on server) * - 'workflow': Trigger GitHub Actions workflow * - Not reachable: Return error with reason */ deployStage(stage: Stage, options?: DeployOptions): Promise; /** * Scan a stage - handles routing based on canReach() * * Returns { handled: true } if pipeline ran scan remotely. * Returns { handled: false } if caller should run scan locally. */ scanStage(stage: Stage, _options?: Record): Promise<{ handled: boolean; }>; /** * Fix a stage - handles routing based on canReach() * * Returns { handled: true } if pipeline ran fix remotely. * Returns { handled: false } if caller should run fix locally. */ fixStage(stage: Stage, _options?: Record): Promise<{ handled: boolean; success?: boolean; error?: string; }>; /** * Run deployment locally by delegating to server plugin */ private runLocalDeploy; /** * Deploy to an environment * @deprecated Use deployStage() which handles routing based on canReach() */ deploy(_config: FactiiiConfig, environment: string): Promise; /** * Undeploy from an environment */ undeploy(_config: FactiiiConfig, environment: string): Promise; } export default FactiiiPipeline; //# sourceMappingURL=index.d.ts.map