over complicated deploy rewrite #187
Draft
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Modern Deploy Experiment - What's Worth Keeping
Hey! I spent some time experimenting with a rewrite of the deploy CLI on the
modern-deploybranch. The goal was to see what improvements we could make without going overboard with architecture. After comparing it with master, here's what I found.The Good Stuff
UI improvements are solid. The switch from
inquirer/gaugeto@clack/promptsmakes a real difference. The prompts look cleaner, handle non-interactive mode better, and the progress indicators are way nicer. Files likesrc/ui/prompts.tsandsrc/ui/progress.tsare drop-in replacements for what we have insrc/cli/.Config validation is actually useful. The
ConfigManagerwith Zod schemas (src/schemas/ConfigSchema.ts) catches config errors early and gives better error messages. The currentsrc/config.tsdoesn't validate anything, so invalid configs can cause weird failures later.Error handling got better. The command suggestions using Levenshtein distance (
src/utils/commandSuggestions.ts) is a nice touch. When someone typesmetacall-deploy deply, it suggestsdeployinstead of just saying "unknown command". Small thing, but it helps.Logging is more structured. The logger in
src/utils/logger.tshas proper levels, colors that fall back gracefully, and timestamps. Our currentsrc/cli/messages.tsis fine but this is more flexible.Inspect output looks better. The table formatting in
src/utils/inspectUtils.tsusingconsole-table-printeris cleaner than what we have. Better alignment, color-coded status, that kind of thing.Utilities are better organized. Instead of one big
src/utils.ts, it's split into focused modules likefileUtils.ts,envUtils.ts,zipUtils.ts. Easier to find things.TypeScript got upgraded. Moving from TS 4.3.2 to 5.5.4 and adding proper types where they matter. Not overdoing it with interfaces everywhere, just using types where they help.
Task lists for deployment progress. Using
listr2to show a nice step-by-step progress indicator during deployment (src/tasks/deploymentTasks.ts). Instead of just printing "Deploying..." and hoping for the best, it shows "Validating deployment configuration", "Preparing deployment", "Deploying to MetaCall" with checkmarks as each step completes. It's currently tied to the strategy pattern, but the concept is solid - we could use it with the simpler function-based approach to give users better visibility into what's happening.What Went Too Far
The strategy pattern for deployments (
src/strategies/) feels like overkill. We havePackageDeploymentStrategyandRepositoryDeploymentStrategywith aDeploymentContextwrapper. The originaldeployPackageanddeployFromRepositoryfunctions are simpler and easier to follow. This abstraction doesn't add value.Factories everywhere.
CommandFactoryis just a switch statement.ProtocolServiceFactoryis a simple conditional. These don't need to be classes. Just use functions or conditionals directly.Too many interfaces. There are interfaces for everything (
ICommand,IProtocolService,IDeploymentStrategy). Some are useful, but a lot of them just add indirection without making the code clearer.Base command classes.
BaseCommandandBaseClipanionCommanduse inheritance for shared options. Composition or helper functions would be simpler.Service layer explosion. We have
DeploymentService,ForceDeploymentService,DeploymentVerificationService,AuthService,PlanService... for operations that were just functions before. The function-based approach is more direct.Builder pattern for config.
DeploymentConfigBuilderfor building a config object? Just use object literals with validation.What I'd Actually Do
If we're going to adopt parts of this, I'd start with the easy wins:
Replace the UI stuff first -
@clack/promptsis a direct upgrade. Swap outsrc/cli/selection.ts,src/cli/progress.ts, andsrc/cli/inputs.tswith the new prompt system (src/ui/prompts.ts,src/ui/progress.ts). Users will notice the difference immediately.Add command suggestions - The Levenshtein distance thing is clever and makes errors less frustrating. Drop
src/utils/commandSuggestions.tsinto the existing error handling.Improve inspect output - The table formatting is better. Replace
src/cli/inspect.tswithsrc/utils/inspectUtils.ts.Add config validation - Replace
src/config.tswith theConfigManagerapproach. The Zod validation catches issues early.Maybe migrate to Clipanion - This one's optional. Clipanion is cleaner than
ts-command-line-args, but it's a bigger change. Could migrate commands one at a time if we want. Seesrc/utils/cliSetup.tsfor the setup.Better logging - Replace
src/cli/messages.tswith the structured logger (src/utils/logger.ts). More flexible for debugging.Organize utilities - Split up
src/utils.tsinto focused modules (src/utils/fileUtils.ts,src/utils/envUtils.ts,src/utils/zipUtils.ts). Makes the codebase easier to navigate.Task lists for deployment - The
listr2task list UI is nice. Shows users what's happening step-by-step during deployment. Currently it's wrapped around the strategy pattern (src/tasks/deploymentTasks.ts, see usage inDeployCommand), but we could use it with the original function-based approach. Just wrap the deployment steps in a Listr task list - "Validating", "Preparing", "Deploying", etc. Much better than the current "Deploying..." message.The retry policy logic is fine, but the class structure is more complex than it needs to be. Keep the exponential backoff idea, simplify the implementation.
Dependencies
We'd need to add:
@clack/prompts(replacesinquirerandgauge)zod(for validation)clipanion(optional, if we migrate commands)listr2(for task lists - nice UX improvement for deployment progress)And could remove:
ts-command-line-args(if we go with Clipanion)inquirerandgauge(replaced by@clack/prompts)Bottom Line
The experiment shows we can improve the UX and code quality without the architectural overhead. The UI improvements, validation, and better error handling are all worth keeping. The strategy patterns, factories, and excessive abstractions? Not so much.
I'd suggest we pick the good parts incrementally. Start with the UI stuff since that's the most visible improvement, then add validation and better error handling. Skip the over-engineered patterns and keep the simple, direct approach that works.