Skip to content

Commit ddca597

Browse files
committed
fix(rollback): plan from requested apply state
1 parent e6639f5 commit ddca597

28 files changed

Lines changed: 632 additions & 241 deletions

TEMPLATES.md

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ schemabot apply -e production
536536
| `schemabot start <apply-id>` | Resume a stopped deployment |
537537
| `schemabot cutover <apply-id>` | Complete a deferred cutover |
538538
| `schemabot rollback <apply-id> -e <env>` | Generate a rollback plan |
539-
| `schemabot rollback-confirm -e <env>` | Execute a rollback |
539+
| `schemabot rollback-confirm <apply-id> -e <env>` | Execute a rollback |
540540

541541
**Options**: `-e <env>` environment, `-d <db>` database, `--defer-cutover`, `--allow-unsafe`, `--skip-revert` (Vitess)
542542

@@ -683,7 +683,7 @@ That command wasn't recognized. Available commands:
683683
| `schemabot start <apply-id>` | Resume a stopped deployment |
684684
| `schemabot cutover <apply-id>` | Complete a deferred cutover |
685685
| `schemabot rollback <apply-id> -e <env>` | Generate a rollback plan |
686-
| `schemabot rollback-confirm -e <env>` | Execute a rollback |
686+
| `schemabot rollback-confirm <apply-id> -e <env>` | Execute a rollback |
687687

688688
**Options**: `-e <env>` environment, `-d <db>` database, `--defer-cutover`, `--allow-unsafe`, `--skip-revert` (Vitess)
689689

@@ -1498,7 +1498,7 @@ Schema changes are being applied. Progress updates will be posted as new comment
14981498
- **`users`**: 🟦🟦🟦🟦🟦🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 48%
14991499

15001500
```sql
1501-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1501+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15021502
```
15031503
Rows: 3,500,000 / 7,200,000 · ETA: 5m 30s
15041504

@@ -1527,7 +1527,7 @@ schemabot stop apply-a1b2c3d4e5f6
15271527
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
15281528

15291529
```sql
1530-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1530+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15311531
```
15321532

15331533

@@ -1548,7 +1548,7 @@ schemabot stop apply-a1b2c3d4e5f6
15481548
- **`users`**: 🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
15491549

15501550
```sql
1551-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1551+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15521552
```
15531553

15541554

@@ -1578,7 +1578,7 @@ schemabot apply -e staging
15781578
- **`users`**: 🟧🟧🟧🟧🟧🟧🟧⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ⏹️ Stopped at 39%
15791579

15801580
```sql
1581-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1581+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15821582
```
15831583
Rows: 156,342 / 397,453
15841584

@@ -1609,19 +1609,19 @@ schemabot start apply-a1b2c3d4e5f6
16091609
- **`orders`**: ⏳ Queued
16101610

16111611
```sql
1612-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1612+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
16131613
```
16141614

16151615
- **`users`**: ⏳ Queued
16161616

16171617
```sql
1618-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1618+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16191619
```
16201620

16211621
- **`products`**: ⏳ Queued
16221622

16231623
```sql
1624-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1624+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
16251625
```
16261626

16271627

@@ -1651,20 +1651,20 @@ schemabot stop apply-a1b2c3d4e5f6
16511651
- **`orders`**: 🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 22%
16521652

16531653
```sql
1654-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1654+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
16551655
```
16561656
Rows: 321,450 / 1,466,232 · ETA: 5m 40s
16571657

16581658
- **`users`**: ⏳ Queued
16591659

16601660
```sql
1661-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1661+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16621662
```
16631663

16641664
- **`products`**: ⏳ Queued
16651665

16661666
```sql
1667-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1667+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
16681668
```
16691669

16701670

@@ -1694,20 +1694,20 @@ schemabot stop apply-a1b2c3d4e5f6
16941694
- **`users`**: 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜ 62%
16951695

16961696
```sql
1697-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1697+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16981698
```
16991699
Rows: 914,707 / 1,466,232 · ETA: 3m 15s
17001700

17011701
- **`products`**: ⏳ Queued
17021702

17031703
```sql
1704-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1704+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17051705
```
17061706

17071707
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17081708

17091709
```sql
1710-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1710+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17111711
```
17121712

17131713

@@ -1737,20 +1737,20 @@ schemabot stop apply-a1b2c3d4e5f6
17371737
- **`products`**: 🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 17%
17381738

17391739
```sql
1740-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1740+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17411741
```
17421742
Rows: 87,231 / 523,140 · ETA: 7m 0s
17431743

17441744
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17451745

17461746
```sql
1747-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1747+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17481748
```
17491749

17501750
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17511751

17521752
```sql
1753-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1753+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
17541754
```
17551755

17561756

@@ -1780,19 +1780,19 @@ schemabot stop apply-a1b2c3d4e5f6
17801780
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17811781

17821782
```sql
1783-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1783+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17841784
```
17851785

17861786
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17871787

17881788
```sql
1789-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1789+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
17901790
```
17911791

17921792
- **`products`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17931793

17941794
```sql
1795-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1795+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17961796
```
17971797

17981798

@@ -1815,19 +1815,19 @@ schemabot stop apply-a1b2c3d4e5f6
18151815
- **`orders`**: 🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
18161816

18171817
```sql
1818-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1818+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
18191819
```
18201820

18211821
- **`users`**: ⊘ Cancelled (not started)
18221822

18231823
```sql
1824-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1824+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
18251825
```
18261826

18271827
- **`products`**: ⊘ Cancelled (not started)
18281828

18291829
```sql
1830-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1830+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
18311831
```
18321832

18331833

@@ -1859,19 +1859,19 @@ schemabot apply -e staging
18591859
- **`users`**: 🟥🟥🟥🟥🟥🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
18601860

18611861
```sql
1862-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1862+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
18631863
```
18641864

18651865
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
18661866

18671867
```sql
1868-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1868+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
18691869
```
18701870

18711871
- **`products`**: ⊘ Cancelled (not started)
18721872

18731873
```sql
1874-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1874+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
18751875
```
18761876

18771877

@@ -1903,14 +1903,14 @@ schemabot apply -e staging
19031903
- **`users`**: 🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬜⬜⬜⬜⬜⬜ ⏹️ Stopped at 72%
19041904

19051905
```sql
1906-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1906+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19071907
```
19081908
Rows: 1,055,687 / 1,466,232
19091909

19101910
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
19111911

19121912
```sql
1913-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1913+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19141914
```
19151915

19161916

@@ -1933,26 +1933,28 @@ schemabot start apply-a1b2c3d4e5f6
19331933

19341934
*Applied by @aparajon at 2026-01-01 00:00:00 UTC*
19351935

1936+
**0/3** table(s) ready for cutover — waiting on 3
1937+
19361938
📊 3 waiting for cutover
19371939

19381940
### Table Progress
19391941

19401942
- **`orders`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19411943

19421944
```sql
1943-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1945+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19441946
```
19451947

19461948
- **`users`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19471949

19481950
```sql
1949-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1951+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19501952
```
19511953

19521954
- **`products`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19531955

19541956
```sql
1955-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1957+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
19561958
```
19571959

19581960

@@ -1975,26 +1977,28 @@ schemabot cutover apply-a1b2c3d4e5f6
19751977

19761978
*Applied by @aparajon at 2026-01-01 00:00:00 UTC*
19771979

1980+
**0/3** table(s) ready for cutover — waiting on 3
1981+
19781982
📊 3 cutting over
19791983

19801984
### Table Progress
19811985

19821986
- **`orders`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19831987

19841988
```sql
1985-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1989+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19861990
```
19871991

19881992
- **`users`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19891993

19901994
```sql
1991-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1995+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19921996
```
19931997

19941998
- **`products`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19951999

19962000
```sql
1997-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
2001+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
19982002
```
19992003

20002004

pkg/api/control_handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ func (s *Service) handleRollbackPlan(w http.ResponseWriter, r *http.Request) {
388388
return
389389
}
390390

391-
resp, err := s.ExecuteRollbackPlan(r.Context(), apply.Database, apply.Environment, apply.Deployment)
391+
resp, err := s.ExecuteRollbackPlanForApply(r.Context(), apply)
392392
if err != nil {
393393
metrics.RecordControlOperation(r.Context(), "rollback_plan", apply.Database, apply.Environment, "error")
394394
s.writeControlError(w, "rollback plan", apply.Database, err)

pkg/api/handlers_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,18 @@ type mockTernClient struct {
5757
skipRevertResp *ternv1.SkipRevertResponse
5858
skipRevertErr error
5959
skipRevertReq *ternv1.SkipRevertRequest // captured request
60+
planResp *ternv1.PlanResponse
61+
planErr error
62+
planReq *ternv1.PlanRequest // captured request
6063
}
6164

6265
func (m *mockTernClient) Health(ctx context.Context) error { return m.healthErr }
6366
func (m *mockTernClient) Plan(ctx context.Context, req *ternv1.PlanRequest) (*ternv1.PlanResponse, error) {
64-
return nil, nil
67+
m.planReq = req
68+
if m.planResp != nil {
69+
return m.planResp, m.planErr
70+
}
71+
return nil, m.planErr
6572
}
6673
func (m *mockTernClient) Apply(ctx context.Context, req *ternv1.ApplyRequest) (*ternv1.ApplyResponse, error) {
6774
return nil, nil
@@ -110,9 +117,6 @@ func (m *mockTernClient) SkipRevert(ctx context.Context, req *ternv1.SkipRevertR
110117
}
111118
return nil, m.skipRevertErr
112119
}
113-
func (m *mockTernClient) RollbackPlan(ctx context.Context, database string) (*ternv1.PlanResponse, error) {
114-
return nil, nil
115-
}
116120
func (m *mockTernClient) ResumeApply(ctx context.Context, apply *storage.Apply) error {
117121
return nil
118122
}

0 commit comments

Comments
 (0)