Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ Generic file migration tool for applying ordered transformations to a project di
migrate status # Show applied/pending migrations
migrate up # Apply all pending migrations
migrate up --dry-run # Preview without applying
migrate up --baseline # Apply and create baseline at final version
migrate up --baseline --keep # Apply and baseline without deleting files
migrate create <name> # Create new bash migration
migrate create <name> --template ts # Create TypeScript migration
migrate create <name> --list-templates # List available templates
migrate baseline <version> # Create baseline at specific version
migrate baseline <version> --dry-run # Preview baseline changes
migrate baseline <version> --keep # Baseline without deleting files
```

## Options
Expand Down Expand Up @@ -68,11 +73,13 @@ await fs.writeFile(`${projectRoot}/config.json`, '{}');
- `src/state.rs` - History tracking (`.history` file)
- `src/version.rs` - Base36 version generation and parsing
- `src/templates.rs` - Embedded migration templates
- `src/baseline.rs` - Baseline management (`.baseline` file)
- `src/commands/` - CLI command implementations
- `mod.rs` - Command module exports
- `status.rs` - Status command (shows version summary)
- `up.rs` - Up command
- `create.rs` - Create command (generates time-based version)
- `baseline.rs` - Baseline command (marks versions as applied)
- `templates/` - Template source files (bash.sh, typescript.ts, python.py, node.js, ruby.rb)

## Development
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "migrate"
version = "0.3.2"
version = "0.4.0"
edition = "2021"
description = "Generic file migration tool for applying ordered transformations to a project directory"
license = "MIT"
Expand Down
168 changes: 101 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,56 +41,47 @@ cargo install migrate
cargo install --git https://github.com/glideapps/migrate
```

## Usage

### Check migration status
## Quick Start

```bash
# Check what migrations exist and their status
migrate status
```

### Apply pending migrations

```bash
# Apply all pending migrations
migrate up
```

### Preview changes without applying

```bash
# Preview what would happen without making changes
migrate up --dry-run
```

### Create a new migration

```bash
# Create a bash migration (default)
migrate create add-prettier
## Migration Lifecycle

# Create a TypeScript migration
migrate create add-config --template ts
### 1. Creating Migrations

# Create with description
migrate create add-prettier -d "Add Prettier configuration"
Create a new migration with `migrate create`:

# List available templates
migrate create --list-templates
```bash
migrate create add-prettier # Bash script (default)
migrate create setup-config --template ts # TypeScript
migrate create init-db --template python # Python
```

## Writing Migrations
This generates a timestamped file like `1fb2g-add-prettier.sh` in your `migrations/` directory. The 5-character prefix ensures migrations run in chronological order.

**Available templates:** `bash`, `ts`, `python`, `node`, `ruby`

Migration files use the format `XXXXX-name.{sh,ts,py,...}` where `XXXXX` is a 5-character base36 version automatically generated by `migrate create`. The version encodes the creation timestamp, ensuring migrations sort chronologically.
### 2. Writing Migrations

Migrations are executable files that receive context via environment variables:

```bash
MIGRATE_PROJECT_ROOT=/path/to/project # Absolute path to project root
MIGRATE_MIGRATIONS_DIR=/path/to/migrations # Where migration files live
MIGRATE_ID=1fb2g-initial-setup # Current migration ID (includes version)
MIGRATE_DRY_RUN=true|false # Whether this is a dry run
```
| Variable | Description |
|----------|-------------|
| `MIGRATE_PROJECT_ROOT` | Absolute path to project root |
| `MIGRATE_MIGRATIONS_DIR` | Where migration files live |
| `MIGRATE_ID` | Current migration ID (e.g., `1fb2g-add-prettier`) |
| `MIGRATE_DRY_RUN` | `true` if running in preview mode |

### Bash example
**Bash example:**

```bash
#!/usr/bin/env bash
Expand All @@ -109,7 +100,7 @@ cat > tsconfig.json << 'EOF'
EOF
```

### TypeScript example
**TypeScript example:**

```typescript
#!/usr/bin/env -S npx tsx
Expand All @@ -120,61 +111,104 @@ import * as path from 'path';

const projectRoot = process.env.MIGRATE_PROJECT_ROOT!;

const config = {
version: 1,
features: ['auth', 'api']
};

await fs.writeFile(
path.join(projectRoot, 'config.json'),
JSON.stringify(config, null, 2)
JSON.stringify({ version: 1 }, null, 2)
);
```

Migrations run in order by their version prefix (e.g., `1fb2g-`) and are tracked in a `.history` file.
### 3. Applying Migrations

Run `migrate up` to apply all pending migrations in order. Each successful migration is recorded in `.history`, so it won't run again.

```bash
migrate up # Apply all pending
migrate up --dry-run # Preview without applying
```

If a migration fails, execution stops immediately. Fix the issue and re-run `migrate up`—already-applied migrations are skipped.

### 4. Checking Status

Use `migrate status` to see what's been applied and what's pending:

```
Version: 1fb2g → 1fc3h (2 pending)

Applied (3):
✓ 1fa1f-init-project
✓ 1fa2g-add-typescript
✓ 1fb2g-setup-eslint

## CLI Reference
Pending (2):
• 1fc2h-add-prettier
• 1fc3h-configure-ci
```

### 5. Baselining (Cleaning Up Old Migrations)

| Command | Description |
| --------------------------- | ----------------------------------- |
| `migrate status` | Show applied and pending migrations |
| `migrate up` | Apply all pending migrations |
| `migrate create <name>` | Create a new migration file |
Over time, your `migrations/` directory accumulates files. Once migrations have been applied everywhere (all environments, all team members), you can **baseline** to clean up.

### Options
Baselining marks a version as the "starting point"—migrations at or before that version are considered complete and can be deleted.

| Option | Description | Default |
| -------------------------- | ------------------------------------- | ------------ |
| `-r, --root <path>` | Project root directory | `.` |
| `-m, --migrations <path>` | Migrations directory | `migrations` |
| `--dry-run` | Preview changes (up only) | `false` |
| `-t, --template <name>` | Template to use (create only) | `bash` |
| `-d, --description <text>` | Migration description (create only) | - |
| `--list-templates` | List available templates (create only)| - |
```bash
# Mark version 1fb2g as baseline and delete old migration files
migrate baseline 1fb2g

## Available Templates
# Preview what would be deleted without making changes
migrate baseline 1fb2g --dry-run

- `bash` - Shell script (`.sh`)
- `ts` - TypeScript via tsx (`.ts`)
- `python` - Python 3 (`.py`)
- `node` - Node.js (`.js`)
- `ruby` - Ruby (`.rb`)
# Create baseline but keep the files (just update .baseline)
migrate baseline 1fb2g --keep
```

You can also baseline immediately after applying migrations:

```bash
migrate up --baseline # Apply and baseline at final version
migrate up --baseline --keep # Apply and baseline without deleting files
```

**When to baseline:**
- All environments have applied the migrations
- All team members have pulled and applied
- You want to reduce clutter in the migrations directory

**What baselining does:**
- Creates/updates `.baseline` file with the baseline version
- Optionally deletes migration files at or before that version
- Future `migrate up` skips migrations covered by the baseline

## Directory Structure

```
your-project/
├── migrations/
│ ├── .history # Tracks applied migrations (auto-generated)
│ ├── .baseline # Baseline marker (optional, from baselining)
│ ├── 1fc2h-add-prettier.sh
│ └── 1fc3h-configure-ci.ts
└── ...
```

## Global Options

These options work with all commands:

| Option | Description | Default |
|--------|-------------|---------|
| `-r, --root <path>` | Project root directory | `.` |
| `-m, --migrations <path>` | Migrations directory | `migrations` |

## Development

```bash
# Clone and setup
git clone <repo-url>
git clone https://github.com/glideapps/migrate
cd migrate
./scripts/setup # Enable git hooks, fetch deps, build, test

# Common commands
cargo build # Build debug binary
cargo nextest run # Run tests
cargo fmt # Format code
cargo clippy # Lint
cargo run -- status # Run CLI locally

# Build release
cargo build --release
```
Loading