acumatica-cli 0.13.0__tar.gz → 0.13.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/PKG-INFO +27 -29
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/README.md +26 -28
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/pyproject.toml +1 -1
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/cli.py +14 -27
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/config.py +63 -164
- acumatica_cli-0.13.1/src/acumatica_cli/templates/README.md +49 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/20-accounts.yaml +2 -2
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/90-uoms.yaml +9 -0
- acumatica_cli-0.13.1/src/acumatica_cli/templates/config/baseline/91-company-packaging.yaml +14 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/bootstrap/company.yaml +1 -1
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/bootstrap/features.yaml +1 -1
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/51-warehouse-locations.yaml +8 -6
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/53-tax-categories.yaml +1 -1
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/75-vendors.yaml +1 -1
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/80-stock-items-parts.yaml +22 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/82-stock-items-kits.yaml +10 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates}/scenario/10-seed-capital.yaml +2 -2
- acumatica_cli-0.13.1/src/acumatica_cli/templates/scenario/20-buy.yaml +361 -0
- acumatica_cli-0.13.1/src/acumatica_cli/templates/scenario/30-build.yaml +136 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates}/scenario/40-sell.yaml +1 -1
- acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution/README.md +0 -87
- acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution/scenario/20-buy-gateways.yaml +0 -112
- acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution/scenario/30-build.yaml +0 -5
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/baseline/20-accounts.yaml +0 -94
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/baseline/60-ledger-company.yaml +0 -27
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/baseline/90-uoms.yaml +0 -16
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/bootstrap/company.yaml +0 -15
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/bootstrap/features.yaml +0 -16
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/setup/30-open-periods.yaml +0 -33
- acumatica_cli-0.13.0/src/acumatica_cli/templates/finance/snapshot/10-trial-balance.yaml +0 -20
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/__init__.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/bootstrap.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/bootstrap_plugin.cs +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/bootstrap_project.xml +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/client.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/extract.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/extract_manifest.yaml +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/firstlogin.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/models.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/output.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/run.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/seed.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/snapshot.py +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/target.py +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/10-subaccounts.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/40-ledger.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/50-gl-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/baseline/60-ledger-company.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/bootstrap/credit-terms.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/10-reason-codes.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/20-in-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/30-availability-rules.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/40-posting-classes.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/50-warehouse.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/52-warehouse-defaults.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/54-item-classes.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/56-so-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/57-po-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/58-order-types.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/60-ar-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/61-ap-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/62-ca-preferences.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/63-cash-account.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/64-payment-methods.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/65-statement-cycles.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/70-vendor-classes.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/71-customer-classes.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/76-customers.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/master/85-kit-specifications.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/setup/10-financial-year.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/setup/20-master-calendar.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/setup/30-open-periods.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/distribution → acumatica_cli-0.13.1/src/acumatica_cli/templates/config}/snapshot/10-trial-balance.yaml +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates}/env +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates}/gitignore +0 -0
- {acumatica_cli-0.13.0/src/acumatica_cli/templates/finance → acumatica_cli-0.13.1/src/acumatica_cli/templates}/target +0 -0
- {acumatica_cli-0.13.0 → acumatica_cli-0.13.1}/src/acumatica_cli/tenant.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: acumatica-cli
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.1
|
|
4
4
|
Summary: Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data
|
|
5
5
|
Author: Konstantin Borovik
|
|
6
6
|
Author-email: Konstantin Borovik <kb@lab5.ca>
|
|
@@ -38,27 +38,23 @@ Acumatica configuration normally lives in the web UI: wizards, screens, and manu
|
|
|
38
38
|
uv tool install acumatica-cli
|
|
39
39
|
|
|
40
40
|
acu config init --host erp.example.com my-erp
|
|
41
|
-
cd my-erp # edit .env: set ACU_PASSWORD
|
|
41
|
+
cd my-erp # edit .env: set ACU_PASSWORD, ACU_TENANT
|
|
42
42
|
# keep ACU_API_VERSION in sync with target.yaml
|
|
43
|
+
# start from a brand-new empty tenant
|
|
43
44
|
|
|
44
45
|
acu config check # read-only preflight (incl. target.yaml)
|
|
45
46
|
acu tenant create --id 3 --login DEV # create the tenant + bootstrap it (needs SSH)
|
|
46
|
-
acu --tenant DEV
|
|
47
|
-
acu --tenant DEV
|
|
47
|
+
# or hosted: acu --tenant DEV bootstrap
|
|
48
|
+
acu --tenant DEV apply config/ # seed config/{bootstrap,baseline,setup,master}/
|
|
49
|
+
acu --tenant DEV run scenario/ # once capital → buy → build → sell
|
|
50
|
+
acu --tenant DEV diff config/ # prove zero drift (exit 2 on drift)
|
|
51
|
+
acu --tenant DEV snapshot # capture state/ trial-balance
|
|
52
|
+
# warm: capital once-skips; Owner Capital stays 50000 (not 100000)
|
|
53
|
+
acu --tenant DEV run scenario/
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```sh
|
|
53
|
-
acu config init --flavor distribution --host erp.example.com my-dist
|
|
54
|
-
cd my-dist # edit .env; start from an empty tenant
|
|
55
|
-
acu config check && acu bootstrap \
|
|
56
|
-
&& acu apply config/ && acu run scenario/ && acu diff config/
|
|
57
|
-
# warm re-run: capital once-skips; Owner Capital stays 50000 (not 100000)
|
|
58
|
-
acu run scenario/
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
See [docs/distribution.md](docs/distribution.md) for the entity map, once-guard, and apply-order notes.
|
|
56
|
+
Bare `apply` / `diff` (no path args) also prefer `config/` when those trees exist.
|
|
57
|
+
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard, and apply-order notes.
|
|
62
58
|
|
|
63
59
|
**Hosted Acumatica (no SSH):** the tenant already exists; leave `ACU_SSH` blank.
|
|
64
60
|
|
|
@@ -67,8 +63,8 @@ acu config init --host customer.acumatica.com my-erp
|
|
|
67
63
|
cd my-erp # edit .env: ACU_TENANT, ACU_PASSWORD; ACU_SSH=
|
|
68
64
|
acu config check # REST preflight; ssh probe is skipped
|
|
69
65
|
acu --tenant DEV bootstrap # publish AcuBootstrap via REST only
|
|
70
|
-
acu --tenant DEV apply
|
|
71
|
-
acu --tenant DEV diff
|
|
66
|
+
acu --tenant DEV apply config/
|
|
67
|
+
acu --tenant DEV diff config/
|
|
72
68
|
# offline UI fallback when REST publish is blocked:
|
|
73
69
|
acu bootstrap --export AcuBootstrap.zip # import + publish on SM204505
|
|
74
70
|
```
|
|
@@ -96,8 +92,7 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
96
92
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
97
93
|
│
|
|
98
94
|
└── config configuration ops
|
|
99
|
-
├── init [--host HOST] [
|
|
100
|
-
│ scaffold a data repo (.env, target.yaml, example YAML)
|
|
95
|
+
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/, target.yaml)
|
|
101
96
|
├── show print the resolved config as a complete .env
|
|
102
97
|
└── check [--strict] preflight: discovery, secrets, target, REST, endpoints, SSH
|
|
103
98
|
```
|
|
@@ -112,21 +107,22 @@ Run `acu <command> --help` for details on any command.
|
|
|
112
107
|
## The data repo
|
|
113
108
|
|
|
114
109
|
Your configuration lives in its own git repo.
|
|
115
|
-
`acu config init` scaffolds
|
|
116
|
-
`acu config init --flavor distribution` scaffolds the full demo under `config/` (same contract identity, expanded COA, masters) plus lifecycle `scenario/` and README.
|
|
110
|
+
`acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/snapshot/`, and README. There is no `--flavor`.
|
|
117
111
|
|
|
118
112
|
| Path | What it holds |
|
|
119
113
|
| ---- | ------------- |
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `config/master/` | distribution masters (prefs, warehouse, items, parties)
|
|
124
|
-
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build
|
|
114
|
+
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms, `project.xml` |
|
|
115
|
+
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs, packaging |
|
|
116
|
+
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
117
|
+
| `config/master/` | inventory/distribution masters (prefs, warehouse, items, parties) |
|
|
118
|
+
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
125
119
|
| `config/snapshot/` | observer views for `acu snapshot` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
126
120
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
127
121
|
| `target.yaml` | committed verified matrix: `erp` + `default_api` (what, not where) |
|
|
128
122
|
| `.env` | where to apply and who signs in, every key an `ACU_*` variable |
|
|
129
123
|
|
|
124
|
+
Legacy data repos may still keep root `bootstrap/`…`master/`; bare `apply`/`diff` prefer `config/` when present and never merge both trees.
|
|
125
|
+
|
|
130
126
|
Files in each directory apply alphabetically; the numbered prefixes (`10-`, `20-`, and so on) encode dependency order.
|
|
131
127
|
The scaffolded `.gitignore` keeps `.env` out of git — store it encrypted (for example as `.env.gpg`) and decrypt once per clone.
|
|
132
128
|
Commit `target.yaml` with the seeds so every clone knows the verified ERP line and Default API generation.
|
|
@@ -306,11 +302,13 @@ Configuration is one file: a decrypted `.env` at the repo root names the instanc
|
|
|
306
302
|
|
|
307
303
|
The tier is self-contained.
|
|
308
304
|
Each run scaffolds a synthetic single-org company from the packaged `acu config init` templates into a temporary directory, copies the real `.env` into it, and runs the installed `acu` binary from there — no data repo, no pre-existing fixtures on the instance.
|
|
309
|
-
Scratch tenants (`E2E`, `E2EA`, `E2EB`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
305
|
+
Scratch tenants (`E2E`, `E2EA`, `E2EB`, `E2ESCEN`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
306
|
+
The packaged full `config init` seed (under `config/`) is the only scaffold.
|
|
310
307
|
|
|
311
308
|
```sh
|
|
312
309
|
gmake e2e # whole tier, about 20 minutes
|
|
313
|
-
gmake e2e FILE=test_provision_lifecycle #
|
|
310
|
+
gmake e2e FILE=test_provision_lifecycle # apply/diff focus
|
|
311
|
+
gmake e2e FILE=test_scenario_lifecycle # scenario + snapshot focus
|
|
314
312
|
```
|
|
315
313
|
|
|
316
314
|
## License
|
|
@@ -20,27 +20,23 @@ Acumatica configuration normally lives in the web UI: wizards, screens, and manu
|
|
|
20
20
|
uv tool install acumatica-cli
|
|
21
21
|
|
|
22
22
|
acu config init --host erp.example.com my-erp
|
|
23
|
-
cd my-erp # edit .env: set ACU_PASSWORD
|
|
23
|
+
cd my-erp # edit .env: set ACU_PASSWORD, ACU_TENANT
|
|
24
24
|
# keep ACU_API_VERSION in sync with target.yaml
|
|
25
|
+
# start from a brand-new empty tenant
|
|
25
26
|
|
|
26
27
|
acu config check # read-only preflight (incl. target.yaml)
|
|
27
28
|
acu tenant create --id 3 --login DEV # create the tenant + bootstrap it (needs SSH)
|
|
28
|
-
acu --tenant DEV
|
|
29
|
-
acu --tenant DEV
|
|
29
|
+
# or hosted: acu --tenant DEV bootstrap
|
|
30
|
+
acu --tenant DEV apply config/ # seed config/{bootstrap,baseline,setup,master}/
|
|
31
|
+
acu --tenant DEV run scenario/ # once capital → buy → build → sell
|
|
32
|
+
acu --tenant DEV diff config/ # prove zero drift (exit 2 on drift)
|
|
33
|
+
acu --tenant DEV snapshot # capture state/ trial-balance
|
|
34
|
+
# warm: capital once-skips; Owner Capital stays 50000 (not 100000)
|
|
35
|
+
acu --tenant DEV run scenario/
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```sh
|
|
35
|
-
acu config init --flavor distribution --host erp.example.com my-dist
|
|
36
|
-
cd my-dist # edit .env; start from an empty tenant
|
|
37
|
-
acu config check && acu bootstrap \
|
|
38
|
-
&& acu apply config/ && acu run scenario/ && acu diff config/
|
|
39
|
-
# warm re-run: capital once-skips; Owner Capital stays 50000 (not 100000)
|
|
40
|
-
acu run scenario/
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
See [docs/distribution.md](docs/distribution.md) for the entity map, once-guard, and apply-order notes.
|
|
38
|
+
Bare `apply` / `diff` (no path args) also prefer `config/` when those trees exist.
|
|
39
|
+
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard, and apply-order notes.
|
|
44
40
|
|
|
45
41
|
**Hosted Acumatica (no SSH):** the tenant already exists; leave `ACU_SSH` blank.
|
|
46
42
|
|
|
@@ -49,8 +45,8 @@ acu config init --host customer.acumatica.com my-erp
|
|
|
49
45
|
cd my-erp # edit .env: ACU_TENANT, ACU_PASSWORD; ACU_SSH=
|
|
50
46
|
acu config check # REST preflight; ssh probe is skipped
|
|
51
47
|
acu --tenant DEV bootstrap # publish AcuBootstrap via REST only
|
|
52
|
-
acu --tenant DEV apply
|
|
53
|
-
acu --tenant DEV diff
|
|
48
|
+
acu --tenant DEV apply config/
|
|
49
|
+
acu --tenant DEV diff config/
|
|
54
50
|
# offline UI fallback when REST publish is blocked:
|
|
55
51
|
acu bootstrap --export AcuBootstrap.zip # import + publish on SM204505
|
|
56
52
|
```
|
|
@@ -78,8 +74,7 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
78
74
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
79
75
|
│
|
|
80
76
|
└── config configuration ops
|
|
81
|
-
├── init [--host HOST] [
|
|
82
|
-
│ scaffold a data repo (.env, target.yaml, example YAML)
|
|
77
|
+
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/, target.yaml)
|
|
83
78
|
├── show print the resolved config as a complete .env
|
|
84
79
|
└── check [--strict] preflight: discovery, secrets, target, REST, endpoints, SSH
|
|
85
80
|
```
|
|
@@ -94,21 +89,22 @@ Run `acu <command> --help` for details on any command.
|
|
|
94
89
|
## The data repo
|
|
95
90
|
|
|
96
91
|
Your configuration lives in its own git repo.
|
|
97
|
-
`acu config init` scaffolds
|
|
98
|
-
`acu config init --flavor distribution` scaffolds the full demo under `config/` (same contract identity, expanded COA, masters) plus lifecycle `scenario/` and README.
|
|
92
|
+
`acu config init` scaffolds a **single full seed** under `config/` (Bootstrap `project.xml` at `Bootstrap/1.0.0`, expanded COA, masters) plus lifecycle `scenario/`, observer `config/snapshot/`, and README. There is no `--flavor`.
|
|
99
93
|
|
|
100
94
|
| Path | What it holds |
|
|
101
95
|
| ---- | ------------- |
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `config/master/` | distribution masters (prefs, warehouse, items, parties)
|
|
106
|
-
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build
|
|
96
|
+
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms, `project.xml` |
|
|
97
|
+
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs, packaging |
|
|
98
|
+
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
99
|
+
| `config/master/` | inventory/distribution masters (prefs, warehouse, items, parties) |
|
|
100
|
+
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
107
101
|
| `config/snapshot/` | observer views for `acu snapshot` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
108
102
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
109
103
|
| `target.yaml` | committed verified matrix: `erp` + `default_api` (what, not where) |
|
|
110
104
|
| `.env` | where to apply and who signs in, every key an `ACU_*` variable |
|
|
111
105
|
|
|
106
|
+
Legacy data repos may still keep root `bootstrap/`…`master/`; bare `apply`/`diff` prefer `config/` when present and never merge both trees.
|
|
107
|
+
|
|
112
108
|
Files in each directory apply alphabetically; the numbered prefixes (`10-`, `20-`, and so on) encode dependency order.
|
|
113
109
|
The scaffolded `.gitignore` keeps `.env` out of git — store it encrypted (for example as `.env.gpg`) and decrypt once per clone.
|
|
114
110
|
Commit `target.yaml` with the seeds so every clone knows the verified ERP line and Default API generation.
|
|
@@ -288,11 +284,13 @@ Configuration is one file: a decrypted `.env` at the repo root names the instanc
|
|
|
288
284
|
|
|
289
285
|
The tier is self-contained.
|
|
290
286
|
Each run scaffolds a synthetic single-org company from the packaged `acu config init` templates into a temporary directory, copies the real `.env` into it, and runs the installed `acu` binary from there — no data repo, no pre-existing fixtures on the instance.
|
|
291
|
-
Scratch tenants (`E2E`, `E2EA`, `E2EB`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
287
|
+
Scratch tenants (`E2E`, `E2EA`, `E2EB`, `E2ESCEN`) are created on the way in and always deleted on the way out, so nothing persists.
|
|
288
|
+
The packaged full `config init` seed (under `config/`) is the only scaffold.
|
|
292
289
|
|
|
293
290
|
```sh
|
|
294
291
|
gmake e2e # whole tier, about 20 minutes
|
|
295
|
-
gmake e2e FILE=test_provision_lifecycle #
|
|
292
|
+
gmake e2e FILE=test_provision_lifecycle # apply/diff focus
|
|
293
|
+
gmake e2e FILE=test_scenario_lifecycle # scenario + snapshot focus
|
|
296
294
|
```
|
|
297
295
|
|
|
298
296
|
## License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "acumatica-cli"
|
|
3
|
-
version = "0.13.
|
|
3
|
+
version = "0.13.1"
|
|
4
4
|
description = "Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data"
|
|
5
5
|
authors = [{ name = "Konstantin Borovik", email = "kb@lab5.ca" }]
|
|
6
6
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
@@ -15,7 +15,6 @@ from click.shell_completion import get_completion_class
|
|
|
15
15
|
from . import bootstrap, extract, firstlogin, output, run, seed, snapshot
|
|
16
16
|
from .client import AcumaticaClient
|
|
17
17
|
from .config import (
|
|
18
|
-
INIT_FLAVORS,
|
|
19
18
|
Instance,
|
|
20
19
|
data_root,
|
|
21
20
|
find_data_root,
|
|
@@ -411,45 +410,33 @@ def config_group() -> None:
|
|
|
411
410
|
help="Hostname substituted into the scaffolded .env ACU_BASE_URL/ACU_SSH "
|
|
412
411
|
"values (default: a placeholder)",
|
|
413
412
|
)
|
|
414
|
-
@click.option(
|
|
415
|
-
"--flavor",
|
|
416
|
-
type=click.Choice(sorted(INIT_FLAVORS), case_sensitive=True),
|
|
417
|
-
default=None,
|
|
418
|
-
help="Template set: omit for finance-minimal (default, offline e2e); "
|
|
419
|
-
"distribution = full virgin-tenant demo seed (master/, scenario/, "
|
|
420
|
-
"expanded COA/features)",
|
|
421
|
-
)
|
|
422
413
|
@click.argument(
|
|
423
414
|
"directory", required=False, type=click.Path(file_okay=False, path_type=Path)
|
|
424
415
|
)
|
|
425
|
-
def config_init(host: str | None,
|
|
426
|
-
"""Scaffold a data repo: .env, .
|
|
416
|
+
def config_init(host: str | None, directory: Path | None) -> None:
|
|
417
|
+
"""Scaffold a data repo: .env, target.yaml, config/ seed, scenario/.
|
|
427
418
|
|
|
428
419
|
Templates ship with the package; every value is a placeholder or a
|
|
429
|
-
verified
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
skipped). DIRECTORY defaults to the
|
|
434
|
-
if absent. No git init, no gpg.
|
|
420
|
+
verified example - no secrets. Single full seed under ``config/``
|
|
421
|
+
(bootstrap/baseline/setup/master) + lifecycle ``scenario/`` +
|
|
422
|
+
``config/snapshot/`` + README; full company ``project.xml``
|
|
423
|
+
(Bootstrap/1.0.0). No ``--flavor`` (V28/T108). Existing files are
|
|
424
|
+
never overwritten (reported as skipped). DIRECTORY defaults to the
|
|
425
|
+
current directory and is created if absent. No git init, no gpg.
|
|
435
426
|
"""
|
|
436
427
|
target = directory or Path.cwd()
|
|
437
|
-
for action, path in scaffold(target, host=host
|
|
428
|
+
for action, path in scaffold(target, host=host):
|
|
438
429
|
suffix = " (exists)" if action == "skip" else ""
|
|
439
430
|
output.data(f"{action} {path}{suffix}")
|
|
440
|
-
# next-step cmds
|
|
431
|
+
# next-step cmds: operator rebuild order after scaffold (V28)
|
|
441
432
|
output.data("")
|
|
442
433
|
output.data("next:")
|
|
443
434
|
output.data(" 1. edit .env (set ACU_PASSWORD, ACU_TENANT; keep ACU_API_VERSION)")
|
|
444
435
|
output.data(" 2. acu config check")
|
|
445
436
|
output.data(" 3. acu bootstrap # or: acu tenant create ... (SSH)")
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
output.data(" 6. acu diff config/")
|
|
450
|
-
else:
|
|
451
|
-
output.data(" 4. acu apply")
|
|
452
|
-
output.data(" 5. acu diff")
|
|
437
|
+
output.data(" 4. acu apply config/")
|
|
438
|
+
output.data(" 5. acu run scenario/")
|
|
439
|
+
output.data(" 6. acu diff config/")
|
|
453
440
|
|
|
454
441
|
|
|
455
442
|
@config_group.command("show")
|
|
@@ -695,7 +682,7 @@ def default_seed_dirs() -> tuple[Path, ...]:
|
|
|
695
682
|
When the data-repo ``config/`` has any SEED_DIRS child, only those
|
|
696
683
|
``config/<name>/`` paths are returned (dual layout never merges with
|
|
697
684
|
root). Else root ``bootstrap/``…``master/`` for present names
|
|
698
|
-
(
|
|
685
|
+
(legacy root layout). The data repo is the .env dir (V3 walk-up). None
|
|
699
686
|
existing is an error - an empty default would make a bare run a silent
|
|
700
687
|
no-op. Paths come back relative to cwd so a bare run prints exactly
|
|
701
688
|
what naming the dirs would.
|
|
@@ -32,156 +32,101 @@ DB_NAME = "AcumaticaDB"
|
|
|
32
32
|
# Dotfiles are stored dotless (wheel tooling tends to drop dotfiles) and
|
|
33
33
|
# mapped to their real names on write.
|
|
34
34
|
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# bootstrap
|
|
39
|
-
# packaged full company contract (bootstrap_project.xml)
|
|
40
|
-
# share Bootstrap/1.0.0 (T81/T82).
|
|
35
|
+
# Single full seed (V28/T108/T109): no --flavor. Package resources mirror
|
|
36
|
+
# dest layout under templates/ (derived from sibling acumatica-gitops seed
|
|
37
|
+
# trees; prune demo/, Makefile, live .env, state/, packaged project.xml).
|
|
38
|
+
# bootstrap project.xml is not a templates/ file: scaffold copies the
|
|
39
|
+
# packaged full company contract (bootstrap_project.xml) → Bootstrap/1.0.0.
|
|
41
40
|
INIT_TEMPLATES = (
|
|
42
|
-
("
|
|
43
|
-
("
|
|
44
|
-
("
|
|
45
|
-
("
|
|
46
|
-
("
|
|
47
|
-
("
|
|
48
|
-
("
|
|
49
|
-
("finance/baseline/60-ledger-company.yaml", "baseline/60-ledger-company.yaml"),
|
|
50
|
-
("finance/baseline/90-uoms.yaml", "baseline/90-uoms.yaml"),
|
|
51
|
-
("finance/bootstrap/company.yaml", "bootstrap/company.yaml"),
|
|
52
|
-
("finance/bootstrap/credit-terms.yaml", "bootstrap/credit-terms.yaml"),
|
|
53
|
-
("finance/bootstrap/features.yaml", "bootstrap/features.yaml"),
|
|
41
|
+
("env", ".env"),
|
|
42
|
+
("gitignore", ".gitignore"),
|
|
43
|
+
("target", "target.yaml"),
|
|
44
|
+
("README.md", "README.md"),
|
|
45
|
+
("config/bootstrap/company.yaml", "config/bootstrap/company.yaml"),
|
|
46
|
+
("config/bootstrap/credit-terms.yaml", "config/bootstrap/credit-terms.yaml"),
|
|
47
|
+
("config/bootstrap/features.yaml", "config/bootstrap/features.yaml"),
|
|
54
48
|
(
|
|
55
|
-
"
|
|
56
|
-
"bootstrap/project.xml",
|
|
49
|
+
"config/bootstrap/project.xml",
|
|
50
|
+
"config/bootstrap/project.xml",
|
|
57
51
|
), # sentinel; see scaffold
|
|
58
|
-
("
|
|
59
|
-
("
|
|
60
|
-
("
|
|
61
|
-
# V28/V32: observer views under config/snapshot/ (not SEED_DIRS; lone config/ ok)
|
|
52
|
+
("config/baseline/10-subaccounts.yaml", "config/baseline/10-subaccounts.yaml"),
|
|
53
|
+
("config/baseline/20-accounts.yaml", "config/baseline/20-accounts.yaml"),
|
|
54
|
+
("config/baseline/40-ledger.yaml", "config/baseline/40-ledger.yaml"),
|
|
62
55
|
(
|
|
63
|
-
"
|
|
64
|
-
"config/
|
|
56
|
+
"config/baseline/50-gl-preferences.yaml",
|
|
57
|
+
"config/baseline/50-gl-preferences.yaml",
|
|
65
58
|
),
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
# Opt-in `--flavor distribution` overlays + extras (V28/V29/T87). Resource
|
|
69
|
-
# paths live under templates/distribution/; dest paths rehome seed under
|
|
70
|
-
# config/ (V30). Overlays replace rehomed finance-minimal files (company
|
|
71
|
-
# LAB5, expanded COA, features, open-periods, uoms). Contract identity is
|
|
72
|
-
# shared (T82) — no distribution-only project.xml. Lifecycle scenarios
|
|
73
|
-
# replace monoscenario buy-sell (V28).
|
|
74
|
-
_SEED_PREFIXES = ("bootstrap/", "baseline/", "setup/", "master/")
|
|
75
|
-
_ROOT_META = frozenset({".env", ".gitignore", "target.yaml"})
|
|
76
|
-
|
|
77
|
-
DISTRIBUTION_TEMPLATES = (
|
|
78
|
-
("distribution/bootstrap/company.yaml", "config/bootstrap/company.yaml"),
|
|
79
|
-
("distribution/bootstrap/features.yaml", "config/bootstrap/features.yaml"),
|
|
80
|
-
("distribution/baseline/20-accounts.yaml", "config/baseline/20-accounts.yaml"),
|
|
81
59
|
(
|
|
82
|
-
"
|
|
60
|
+
"config/baseline/60-ledger-company.yaml",
|
|
83
61
|
"config/baseline/60-ledger-company.yaml",
|
|
84
62
|
),
|
|
85
|
-
("
|
|
86
|
-
("distribution/setup/30-open-periods.yaml", "config/setup/30-open-periods.yaml"),
|
|
87
|
-
("distribution/master/10-reason-codes.yaml", "config/master/10-reason-codes.yaml"),
|
|
63
|
+
("config/baseline/90-uoms.yaml", "config/baseline/90-uoms.yaml"),
|
|
88
64
|
(
|
|
89
|
-
"
|
|
90
|
-
"config/
|
|
65
|
+
"config/baseline/91-company-packaging.yaml",
|
|
66
|
+
"config/baseline/91-company-packaging.yaml",
|
|
91
67
|
),
|
|
68
|
+
("config/setup/10-financial-year.yaml", "config/setup/10-financial-year.yaml"),
|
|
69
|
+
("config/setup/20-master-calendar.yaml", "config/setup/20-master-calendar.yaml"),
|
|
70
|
+
("config/setup/30-open-periods.yaml", "config/setup/30-open-periods.yaml"),
|
|
71
|
+
("config/master/10-reason-codes.yaml", "config/master/10-reason-codes.yaml"),
|
|
72
|
+
("config/master/20-in-preferences.yaml", "config/master/20-in-preferences.yaml"),
|
|
92
73
|
(
|
|
93
|
-
"
|
|
74
|
+
"config/master/30-availability-rules.yaml",
|
|
94
75
|
"config/master/30-availability-rules.yaml",
|
|
95
76
|
),
|
|
77
|
+
("config/master/40-posting-classes.yaml", "config/master/40-posting-classes.yaml"),
|
|
78
|
+
("config/master/50-warehouse.yaml", "config/master/50-warehouse.yaml"),
|
|
96
79
|
(
|
|
97
|
-
"
|
|
98
|
-
"config/master/40-posting-classes.yaml",
|
|
99
|
-
),
|
|
100
|
-
("distribution/master/50-warehouse.yaml", "config/master/50-warehouse.yaml"),
|
|
101
|
-
(
|
|
102
|
-
"distribution/master/51-warehouse-locations.yaml",
|
|
80
|
+
"config/master/51-warehouse-locations.yaml",
|
|
103
81
|
"config/master/51-warehouse-locations.yaml",
|
|
104
82
|
),
|
|
105
83
|
(
|
|
106
|
-
"
|
|
84
|
+
"config/master/52-warehouse-defaults.yaml",
|
|
107
85
|
"config/master/52-warehouse-defaults.yaml",
|
|
108
86
|
),
|
|
87
|
+
("config/master/53-tax-categories.yaml", "config/master/53-tax-categories.yaml"),
|
|
88
|
+
("config/master/54-item-classes.yaml", "config/master/54-item-classes.yaml"),
|
|
89
|
+
("config/master/56-so-preferences.yaml", "config/master/56-so-preferences.yaml"),
|
|
90
|
+
("config/master/57-po-preferences.yaml", "config/master/57-po-preferences.yaml"),
|
|
91
|
+
("config/master/58-order-types.yaml", "config/master/58-order-types.yaml"),
|
|
92
|
+
("config/master/60-ar-preferences.yaml", "config/master/60-ar-preferences.yaml"),
|
|
93
|
+
("config/master/61-ap-preferences.yaml", "config/master/61-ap-preferences.yaml"),
|
|
94
|
+
("config/master/62-ca-preferences.yaml", "config/master/62-ca-preferences.yaml"),
|
|
95
|
+
("config/master/63-cash-account.yaml", "config/master/63-cash-account.yaml"),
|
|
96
|
+
("config/master/64-payment-methods.yaml", "config/master/64-payment-methods.yaml"),
|
|
109
97
|
(
|
|
110
|
-
"
|
|
111
|
-
"config/master/53-tax-categories.yaml",
|
|
112
|
-
),
|
|
113
|
-
("distribution/master/54-item-classes.yaml", "config/master/54-item-classes.yaml"),
|
|
114
|
-
(
|
|
115
|
-
"distribution/master/56-so-preferences.yaml",
|
|
116
|
-
"config/master/56-so-preferences.yaml",
|
|
117
|
-
),
|
|
118
|
-
(
|
|
119
|
-
"distribution/master/57-po-preferences.yaml",
|
|
120
|
-
"config/master/57-po-preferences.yaml",
|
|
121
|
-
),
|
|
122
|
-
("distribution/master/58-order-types.yaml", "config/master/58-order-types.yaml"),
|
|
123
|
-
(
|
|
124
|
-
"distribution/master/60-ar-preferences.yaml",
|
|
125
|
-
"config/master/60-ar-preferences.yaml",
|
|
126
|
-
),
|
|
127
|
-
(
|
|
128
|
-
"distribution/master/61-ap-preferences.yaml",
|
|
129
|
-
"config/master/61-ap-preferences.yaml",
|
|
130
|
-
),
|
|
131
|
-
(
|
|
132
|
-
"distribution/master/62-ca-preferences.yaml",
|
|
133
|
-
"config/master/62-ca-preferences.yaml",
|
|
134
|
-
),
|
|
135
|
-
("distribution/master/63-cash-account.yaml", "config/master/63-cash-account.yaml"),
|
|
136
|
-
(
|
|
137
|
-
"distribution/master/64-payment-methods.yaml",
|
|
138
|
-
"config/master/64-payment-methods.yaml",
|
|
139
|
-
),
|
|
140
|
-
(
|
|
141
|
-
"distribution/master/65-statement-cycles.yaml",
|
|
98
|
+
"config/master/65-statement-cycles.yaml",
|
|
142
99
|
"config/master/65-statement-cycles.yaml",
|
|
143
100
|
),
|
|
101
|
+
("config/master/70-vendor-classes.yaml", "config/master/70-vendor-classes.yaml"),
|
|
144
102
|
(
|
|
145
|
-
"
|
|
146
|
-
"config/master/70-vendor-classes.yaml",
|
|
147
|
-
),
|
|
148
|
-
(
|
|
149
|
-
"distribution/master/71-customer-classes.yaml",
|
|
103
|
+
"config/master/71-customer-classes.yaml",
|
|
150
104
|
"config/master/71-customer-classes.yaml",
|
|
151
105
|
),
|
|
152
|
-
("
|
|
153
|
-
("
|
|
106
|
+
("config/master/75-vendors.yaml", "config/master/75-vendors.yaml"),
|
|
107
|
+
("config/master/76-customers.yaml", "config/master/76-customers.yaml"),
|
|
154
108
|
(
|
|
155
|
-
"
|
|
109
|
+
"config/master/80-stock-items-parts.yaml",
|
|
156
110
|
"config/master/80-stock-items-parts.yaml",
|
|
157
111
|
),
|
|
158
112
|
(
|
|
159
|
-
"
|
|
113
|
+
"config/master/82-stock-items-kits.yaml",
|
|
160
114
|
"config/master/82-stock-items-kits.yaml",
|
|
161
115
|
),
|
|
162
116
|
(
|
|
163
|
-
"
|
|
117
|
+
"config/master/85-kit-specifications.yaml",
|
|
164
118
|
"config/master/85-kit-specifications.yaml",
|
|
165
119
|
),
|
|
166
120
|
(
|
|
167
|
-
"
|
|
168
|
-
"scenario/10-seed-capital.yaml",
|
|
169
|
-
),
|
|
170
|
-
(
|
|
171
|
-
"distribution/scenario/20-buy-gateways.yaml",
|
|
172
|
-
"scenario/20-buy-gateways.yaml",
|
|
173
|
-
),
|
|
174
|
-
("distribution/scenario/30-build.yaml", "scenario/30-build.yaml"),
|
|
175
|
-
("distribution/scenario/40-sell.yaml", "scenario/40-sell.yaml"),
|
|
176
|
-
(
|
|
177
|
-
"distribution/snapshot/10-trial-balance.yaml",
|
|
121
|
+
"config/snapshot/10-trial-balance.yaml",
|
|
178
122
|
"config/snapshot/10-trial-balance.yaml",
|
|
179
123
|
),
|
|
180
|
-
("
|
|
124
|
+
("scenario/10-seed-capital.yaml", "scenario/10-seed-capital.yaml"),
|
|
125
|
+
("scenario/20-buy.yaml", "scenario/20-buy.yaml"),
|
|
126
|
+
("scenario/30-build.yaml", "scenario/30-build.yaml"),
|
|
127
|
+
("scenario/40-sell.yaml", "scenario/40-sell.yaml"),
|
|
181
128
|
)
|
|
182
129
|
|
|
183
|
-
INIT_FLAVORS = frozenset({"distribution"})
|
|
184
|
-
|
|
185
130
|
|
|
186
131
|
class Instance(BaseSettings):
|
|
187
132
|
"""The resolved target: flags over ACU_* vars (.env or process) over defaults.
|
|
@@ -243,72 +188,26 @@ class Instance(BaseSettings):
|
|
|
243
188
|
return v
|
|
244
189
|
|
|
245
190
|
|
|
246
|
-
def
|
|
247
|
-
"""Resolve (resource, dest) pairs for ``config init`` (V28/T87).
|
|
248
|
-
|
|
249
|
-
Absent flavor → finance-minimal ``INIT_TEMPLATES`` at root (+ observer
|
|
250
|
-
``config/snapshot/``). ``distribution`` keeps root meta
|
|
251
|
-
(``.env``/``.gitignore``/``target.yaml``), rehomes finance seed under
|
|
252
|
-
``config/``, then overlays ``DISTRIBUTION_TEMPLATES`` (config/ seeds +
|
|
253
|
-
lifecycle ``scenario/`` + ``config/snapshot/`` + README). Never dual
|
|
254
|
-
root+config seed trees. Paths already under ``config/`` (snapshot
|
|
255
|
-
views) pass through unchanged.
|
|
256
|
-
"""
|
|
257
|
-
if flavor is None:
|
|
258
|
-
return INIT_TEMPLATES
|
|
259
|
-
if flavor not in INIT_FLAVORS:
|
|
260
|
-
raise SystemExit(
|
|
261
|
-
f"unknown config init flavor {flavor!r}; "
|
|
262
|
-
f"known: {', '.join(sorted(INIT_FLAVORS))}"
|
|
263
|
-
)
|
|
264
|
-
by_dest: dict[str, str] = {}
|
|
265
|
-
order: list[str] = []
|
|
266
|
-
for res, dest in INIT_TEMPLATES:
|
|
267
|
-
if dest in _ROOT_META:
|
|
268
|
-
by_dest[dest] = res
|
|
269
|
-
order.append(dest)
|
|
270
|
-
continue
|
|
271
|
-
if dest.startswith("config/"):
|
|
272
|
-
target = dest
|
|
273
|
-
else:
|
|
274
|
-
target = (
|
|
275
|
-
f"config/{dest}"
|
|
276
|
-
if any(dest.startswith(p) for p in _SEED_PREFIXES)
|
|
277
|
-
else dest
|
|
278
|
-
)
|
|
279
|
-
if target not in by_dest:
|
|
280
|
-
order.append(target)
|
|
281
|
-
by_dest[target] = res
|
|
282
|
-
for res, dest in DISTRIBUTION_TEMPLATES:
|
|
283
|
-
if dest not in by_dest:
|
|
284
|
-
order.append(dest)
|
|
285
|
-
by_dest[dest] = res
|
|
286
|
-
return tuple((by_dest[dest], dest) for dest in order)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
def scaffold(
|
|
290
|
-
directory: Path, host: str | None = None, flavor: str | None = None
|
|
291
|
-
) -> Iterator[tuple[str, Path]]:
|
|
191
|
+
def scaffold(directory: Path, host: str | None = None) -> Iterator[tuple[str, Path]]:
|
|
292
192
|
"""Write the data-repo template set into ``directory``, never overwriting.
|
|
293
193
|
|
|
294
194
|
Yields ("write" | "skip", path) per template file. ``host`` replaces the
|
|
295
195
|
placeholder host inside the scaffolded .env ``ACU_BASE_URL``/``ACU_SSH``
|
|
296
|
-
values; secrets stay placeholders (V2).
|
|
297
|
-
|
|
298
|
-
No git init, no gpg - version control
|
|
299
|
-
operator's call.
|
|
196
|
+
values; secrets stay placeholders (V2). Single full seed under
|
|
197
|
+
``config/`` + lifecycle ``scenario/`` (V28/T108; no flavor). The
|
|
198
|
+
directory is created if absent. No git init, no gpg - version control
|
|
199
|
+
and secret encryption stay the operator's call.
|
|
300
200
|
"""
|
|
301
201
|
pkg = resources.files("acumatica_cli") / "templates"
|
|
302
202
|
directory.mkdir(parents=True, exist_ok=True)
|
|
303
|
-
for resource, dest in
|
|
203
|
+
for resource, dest in INIT_TEMPLATES:
|
|
304
204
|
target = directory / dest
|
|
305
205
|
if target.exists():
|
|
306
206
|
yield "skip", target
|
|
307
207
|
continue
|
|
308
208
|
# Single full contract (T81/T82): scaffold from the packaged
|
|
309
209
|
# bootstrap_project.xml so init cannot diverge from the fallback.
|
|
310
|
-
|
|
311
|
-
if dest in ("bootstrap/project.xml", "config/bootstrap/project.xml"):
|
|
210
|
+
if dest == "config/bootstrap/project.xml":
|
|
312
211
|
content = (
|
|
313
212
|
resources.files("acumatica_cli") / "bootstrap_project.xml"
|
|
314
213
|
).read_text(encoding="utf-8")
|