Skip to content

Latest commit

 

History

History
225 lines (173 loc) · 9.7 KB

File metadata and controls

225 lines (173 loc) · 9.7 KB

🚀 Automated Deploy CLI — Complete Project Walkthrough

What Is This Project?

automatic-deploy is an npm-installable CLI tool (command name: mydeploy) that takes a web project, auto-generates a production Dockerfile using Google Gemini AI, and then deploys the containerised app to AWS ECS (Fargate) — all in one or two commands.

It is published at npm as automatic-deploy (v1.0.4) and authored by Arnav Kumar & Yash Agarwal.


High-Level Architecture

flowchart LR
    subgraph CLI["bin/cli.js"]
        A["mydeploy init"] 
        B["mydeploy config"]
        C["mydeploy deploy"]
    end

    subgraph AI["src/ai/"]
        D["detectFramework()"]
        E["generateDockerfile() via Gemini"]
        F["fallbackTemplate() via EJS"]
    end

    subgraph AWS["src/aws/"]
        G["createResources()"]
        H["pushToECR()"]
        I["deployToECS()"]
    end

    subgraph Utils["src/utils/"]
        J["Logger (ora/chalk)"]
        K["buildDockerImage()"]
        L["writeEnvKey()"]
    end

    A --> D --> E --> F
    C --> K --> G --> H --> I
    B --> L
    AI --> J
    AWS --> J
Loading

The Three CLI Commands

1. mydeploy init [project-path]

Purpose: Analyze a project, detect its framework, and generate a production-ready Dockerfile.

Flow (init.js → analyzeProject.js):

  1. Framework detection — Scans the target directory for telltale files:

    File Found Framework Detected
    package.json with express dependency node-express
    requirements.txt containing django python-django
    go.mod go
    pom.xml java-springboot
  2. AI-powered Dockerfile generation — If a Gemini API key is configured:

    • Reads the project's manifest file (package.json, requirements.txt, go.mod, or pom.xml)
    • Sends it to Gemini 2.0 Flash with a prompt asking for a production-ready Dockerfile
    • Strips any markdown fences from the response and writes the Dockerfile
  3. Template fallback — If AI fails or is disabled (--no-ai), it uses pre-built EJS templates from src/templates/:

    • Dockerfile-node-express.ejs — Multi-stage Node 18 Alpine build
    • Dockerfile-python-django.ejs — Python 3.11 slim + Gunicorn
    • Dockerfile-go.ejs — Multi-stage Go 1.22 Alpine build
    • Dockerfile-java-springboot.ejs — Eclipse Temurin 21 + Maven

Tip

Use --force to overwrite an existing Dockerfile. Use --no-ai to skip Gemini entirely and use templates.


2. mydeploy config <action> <key> [value]

Purpose: Manage API keys and credentials via a .env file.

Flow (config.js → env.js):

Action Example What It Does
set mydeploy config set GEMINI_API_KEY abc123 Writes key=value into .env
get mydeploy config get AWS_REGION Reads from process.env (loaded by dotenv at startup)
  • setConfig() converts the key to uppercase, then calls writeEnvKey() which parses the existing .env, upserts the key, and rewrites the file.
  • Sensitive values (containing "key", "secret", "token", "password") are masked in console output (e.g., abcd****xyz1).
  • There's also a ~/.mydeploy/config.json system for persistent config (used by removeConfig, listConfig, initConfig), though the primary set/get path uses .env.

3. mydeploy deploy [project-path]

Purpose: Build the Docker image, provision all required AWS infrastructure, push to ECR, and deploy to ECS Fargate.

Flow (deploy.js → docker.js → createResources.js → deployToECS.js):

This is the most complex command. It runs a 4-step pipeline:

Step 1: Build Docker Image

docker.js — Runs docker build -t <image-name> . using execa. Requires a Dockerfile to exist (run init first).

Step 2: Create AWS Resources

createResources.js — Idempotently provisions everything needed:

flowchart TD
    A["STS: Get Account ID"] --> B["ECR: Create/find repository"]
    A --> C["ECS: Create/find cluster (Fargate)"]
    A --> D["IAM: Create ecsTaskExecutionRole"]
    A --> E["IAM: Create ecsTaskRole"]
    A --> F["EC2: Find default VPC + subnets"]
    F --> G["EC2: Create security group (ports 80, 443, 3000)"]
    B & C & D & E & G --> H["ECS: Register task definition"]
    H --> I["ECS: Create/find service (desiredCount=1)"]
Loading

Key details:

  • Uses AWS SDK v3 (@aws-sdk/client-ecs, client-ecr, client-iam, client-ec2, client-sts)
  • Every resource uses an ensure pattern — check if it exists first, create only if missing
  • Task definition defaults: 256 CPU / 512 MB memory, port 3000, with CloudWatch Logs configured
  • Security group opens ports 80, 443, and 3000 to 0.0.0.0/0

Step 3: Push to ECR

deployToECS.js → pushToECR():

  1. Gets ECR authorization token
  2. Runs docker login to the ECR endpoint
  3. Tags and pushes the local image as <repo-uri>:latest

Step 4: Update ECS Service

deployToECS.js → deployToECS():

  1. Fetches the current task definition from the running service
  2. Registers a new revision with the updated image URI
  3. Calls UpdateServiceCommand with forceNewDeployment: true
  4. Polls DescribeServicesCommand every 15 seconds (up to 10 minutes) until runningCount === desiredCount
  5. Throws on failure events (e.g., "was stopped", "failed", "unable to place")

Project Structure Summary

automated-deploy/
├── bin/
│   └── cli.js                          # Entry point, Commander.js setup, preflight checks
├── src/
│   ├── ai/
│   │   └── analyzeProject.js           # Framework detection + Gemini Dockerfile generation
│   ├── aws/
│   │   ├── createResources.js          # Idempotent AWS infra provisioning (ECR, ECS, IAM, VPC, SG)
│   │   └── deployToECS.js             # ECR push + ECS task update + stability polling
│   ├── commands/
│   │   ├── init.js                     # Thin wrapper → analyzeProject()
│   │   ├── deploy.js                   # Orchestrates the 4-step deploy pipeline
│   │   └── config.js                   # Config get/set/remove/list + .env management
│   ├── templates/
│   │   ├── Dockerfile-node-express.ejs # Fallback Dockerfile for Node/Express
│   │   ├── Dockerfile-python-django.ejs# Fallback Dockerfile for Django
│   │   ├── Dockerfile-go.ejs          # Fallback Dockerfile for Go
│   │   └── Dockerfile-java-springboot.ejs # Fallback Dockerfile for Spring Boot
│   └── utils/
│       ├── logger.js                   # Rich logging (chalk + ora spinners + tables)
│       ├── docker.js                   # Docker image build via execa
│       └── env.js                      # .env file read/write utility
├── package.json
├── Readme.md
└── .gitignore

Key Dependencies

Package Purpose
commander CLI framework (commands, options, arguments)
@google/generative-ai Google Gemini API for AI Dockerfile generation
@aws-sdk/client-* AWS SDK v3 (ECS, ECR, IAM, EC2, STS, CloudWatch Logs)
execa Subprocess execution (docker build/push/login)
ejs Template rendering for fallback Dockerfiles
inquirer Interactive CLI prompts (installed but not heavily used yet)
ora Terminal spinners for long-running operations
chalk Coloured terminal output
figlet ASCII art text (installed, not currently used in code)
dotenv .env file loading
fs-extra Enhanced filesystem operations

Global CLI Options

Flag Effect
-v, --verbose Shows debug output, docker build logs, full stack traces
--dry-run Prints what would happen without executing anything
--profile <name> Sets AWS_PROFILE for the session
--region <region> Sets AWS_DEFAULT_REGION for the session

Typical Usage Flow

# 1. Install globally
npm install -g automatic-deploy

# 2. Configure credentials
mydeploy config set GEMINI_API_KEY your-gemini-key
mydeploy config set AWS_ACCESS_KEY_ID your-aws-key
mydeploy config set AWS_SECRET_ACCESS_KEY your-aws-secret

# 3. Analyze project & generate Dockerfile
mydeploy init ./my-express-app

# 4. Deploy to AWS ECS
mydeploy deploy ./my-express-app --region us-east-1

Important

The deploy command requires Docker to be installed and running locally, plus valid AWS credentials with permissions for ECS, ECR, IAM, EC2, STS, and CloudWatch Logs.