You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A CLI tool for migrating [commercetools Checkout](https://docs.commercetools.com/checkout) resources between projects — for example when moving from one cloud provider or region to another.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
8
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
9
+
10
+
-[What is this?](#what-is-this)
11
+
-[Prerequisites](#prerequisites)
12
+
-[Usage](#usage)
13
+
-[Running the Docker Image](#running-the-docker-image)
14
+
-[Build](#build)
15
+
-[Run](#run)
16
+
-[Examples](#examples)
17
+
-[Sync Behaviour](#sync-behaviour)
18
+
-[Applications](#applications)
19
+
-[Payment Integrations](#payment-integrations)
20
+
-[Scopes](#scopes)
21
+
22
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
23
+
24
+
### What is this?
25
+
26
+
A Dockerized CLI application which migrates [commercetools Checkout](https://docs.commercetools.com/checkout) resources between projects — for example when moving between cloud providers or regions.
27
+
28
+
The following resource types are supported, synced in this order:
29
+
30
+
-**Applications**
31
+
-**Payment Integrations**
32
+
33
+
Applications are synced first because Payment Integrations reference them by ID. The tool builds a `sourceAppID → targetAppID` map during the application phase and uses it to rewrite references before touching payment integrations.
34
+
35
+
### Prerequisites
36
+
37
+
- Docker (to run the image) or Go 1.21+ (to build from source)
38
+
- A commercetools API client with Checkout permissions on both source and target projects
39
+
- A `config.yml` file — copy the example and fill in your credentials:
40
+
41
+
```bash
42
+
cp config.example.yml config.yml
43
+
```
44
+
45
+
```yaml
46
+
source:
47
+
project_key: "source-project-key"
48
+
client_id: "sourceClientId"
49
+
client_secret: "sourceClientSecret"
50
+
# OAuth token endpoint (Composable Commerce), not the Checkout API host.
By default the tool runs in **dry-run** mode: it compares source and target resources and prints a plan without writing anything. Pass `-f` to execute the migration.
86
92
87
-
### Dry-run (default)
93
+
#### Running the Docker Image
88
94
89
-
Shows exactly what would be created or updated — no changes are made:
95
+
##### Build
90
96
91
97
```bash
92
-
./checkout-cloud-sync -c config.yml
98
+
docker build -t checkout-cloud-sync .
93
99
```
94
100
95
-
#### Docker
101
+
##### Run
96
102
97
103
Mount your `config.yml` at `/app/config.yml` via a volume — credentials must never be baked into the image.
98
104
99
105
```bash
100
-
# Dry-run (default)
101
-
docker run --rm -v $(pwd)/config.yml:/app/config.yml checkout-cloud-sync
102
-
103
-
# Execute migration
104
-
docker run --rm -v $(pwd)/config.yml:/app/config.yml checkout-cloud-sync -f
106
+
docker run --rm \
107
+
-v $(pwd)/config.yml:/app/config.yml \
108
+
checkout-cloud-sync
105
109
```
106
110
107
-
Example output:
108
-
109
-
```
110
-
=== DRY RUN — pass -f to execute ===
111
+
### Examples
111
112
112
-
--- Applications ---
113
-
Found 2 application(s) in source project "source-project-key"
113
+
- To perform a dry-run (default):
114
+
```bash
115
+
docker run --rm -v $(pwd)/config.yml:/app/config.yml checkout-cloud-sync
116
+
```
114
117
115
-
[CREATE] application "my-application"
116
-
[SKIP] application "existing-app" — already up to date
118
+
Example output:
119
+
```
120
+
=== DRY RUN — pass -f to execute ===
117
121
118
-
Applications: 1 to create, 0 to update, 1 skipped/errors
122
+
--- Applications ---
123
+
Found 2 application(s) in source project "source-project-key"
119
124
120
-
--- Payment Integrations ---
121
-
Found 3 payment integration(s) in source project "source-project-key"
125
+
[CREATE] application "my-application"
126
+
[SKIP] application "existing-app" — already up to date
Payment integrations are matched against target resources using a two-step lookup:
171
185
172
186
1.**Exact key match** — looks up the source key in the target index.
173
-
2. **Name fallback** — if no key match, looks up by `name`. When a name match is found with a different key, the target key is considered stale and a `setKey` action is prepended to the update. This handles the case where a payment integration's key is changed in the source project.
187
+
2.**Name fallback** — if no key match, looks up by `name`. When a name match is found with a different key, the target key is considered stale and a `setKey` action is prepended to the update. This handles key renames in the source project.
174
188
175
-
> **Note:** If multiple target payment integrations share the same name, the name index entry is removed to prevent ambiguous matching. In that case, a missing key match results in a new resource being created.
189
+
> **Note:** If multiple target payment integrations share the same name, the name index entry is removed to prevent ambiguous matching. A missing key match in that case results in a new resource being created.
176
190
177
191
| Condition | Action |
178
-
|-----------|--------|
192
+
|---|---|
179
193
| No match by key or name |`CREATE`|
180
194
| Key match, no fields differ |`SKIP`|
181
195
| Key match, fields differ |`UPDATE`|
182
196
| Name match, key differs |`UPDATE` with `setKey` prepended |
183
197
184
198
The following update actions are used: `setKey`, `setName`, `setStatus`, `setComponentType`, `setPredicate`, `setDisplayInfo`, `setSortingInfo`, `setAutomatedReversalConfiguration`, `setConnectorDeployment`.
185
199
186
-
#### Application ID translation
200
+
**Key derivation for keyless integrations**
187
201
188
-
Payment integrations reference their parent application by ID. Since application IDs differ between projects, the tool builds a `sourceAppID → targetAppID` map during the application sync phase and uses it to rewrite references before creating or updating payment integrations in the target.
202
+
When a payment integration has no `key`, one is derived from the combination of its source **ID** and **name**: `{sanitised-id}-{sanitised-name}`. Using the source ID as a prefix guarantees that two integrations sharing the same display name receive distinct keys.
189
203
190
-
#### Connector deployment mapping
204
+
**Connector deployment mapping**
191
205
192
206
Connector deployment IDs are environment-specific. Any payment integration that has a `connectorDeployment`**must** have its source deployment UUID listed in `deployment_mapping`. Without a mapping entry the integration is skipped with a clear error:
193
207
@@ -196,46 +210,17 @@ payment integration "credit-card-via-adyen": connectorDeployment "src-uuid" has
196
210
in deployment_mapping — add it under deployment_mapping in config.yml and retry
197
211
```
198
212
199
-
---
200
-
201
-
## Error handling
213
+
**Error handling**
202
214
203
215
Errors on individual resources are non-fatal. The tool logs each failure, continues processing the remaining resources, and exits with a non-zero status when any error occurred. This means a single bad resource never blocks the rest of the migration.
204
216
205
-
---
206
-
207
-
## Development
217
+
## Scopes
208
218
209
-
```bash
210
-
# Run tests
211
-
go test ./...
212
-
213
-
# Run tests with race detector
214
-
go test -race ./...
215
-
216
-
# Run with coverage
217
-
go test -cover ./...
218
-
219
-
# Build
220
-
go build -o checkout-cloud-sync .
221
-
```
222
-
223
-
### Project structure
219
+
For least-privilege access, use the following scopes instead of `manage_project`:
224
220
225
-
```
226
-
checkout-cloud-sync/
227
-
├── main.go
228
-
├── config.example.yml
229
-
├── cmd/
230
-
│ └── root.go # CLI flags and entry point
231
-
└── internal/
232
-
├── config/
233
-
│ └── config.go # YAML config loading and validation
0 commit comments