acumatica-cli 0.18.2__tar.gz → 0.25.2__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.18.2 → acumatica_cli-0.25.2}/PKG-INFO +114 -47
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/README.md +113 -46
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/pyproject.toml +7 -2
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/pyproject.toml.orig +4 -1
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/bootstrap.py +35 -20
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/bootstrap_project.xml +313 -5
- acumatica_cli-0.25.2/src/acumatica_cli/cli.py +1897 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/client.py +36 -2
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/config.py +96 -49
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/extract.py +10 -1
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/inventory.py +1 -1
- acumatica_cli-0.25.2/src/acumatica_cli/matrix.py +155 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/reconcile.py +10 -4
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/run.py +69 -24
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/seed.py +141 -37
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/seed_catalog.yaml +103 -6
- acumatica_cli-0.25.2/src/acumatica_cli/snapshot_map.yaml +314 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/state.py +1 -1
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/README.md +19 -8
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/20-accounts.yaml +24 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/50-gl-preferences.yaml +4 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/config/master/05-numbering-sequences.yaml +82 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/20-in-preferences.yaml +9 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/56-so-preferences.yaml +2 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/57-po-preferences.yaml +3 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +12 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +12 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/62-ca-preferences.yaml +4 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/config/master/90-roles.yaml +214 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/config/master/91-users.yaml +16 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/env +15 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/matrix +9 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/overlays/README.md +51 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/overlays/default-24.200.001/README.md +11 -0
- acumatica_cli-0.25.2/src/acumatica_cli/templates/overlays/default-24.200.001/scenario/30-build.yaml +116 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/scenario/10-seed-capital.yaml +3 -3
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/scenario/20-buy.yaml +3 -3
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/scenario/30-build.yaml +1 -1
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/scenario/40-sell.yaml +4 -4
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/tenant.py +21 -5
- acumatica_cli-0.18.2/src/acumatica_cli/cli.py +0 -1221
- acumatica_cli-0.18.2/src/acumatica_cli/snapshot_map.yaml +0 -167
- acumatica_cli-0.18.2/src/acumatica_cli/target.py +0 -94
- acumatica_cli-0.18.2/src/acumatica_cli/templates/config/master/60-ar-preferences.yaml +0 -5
- acumatica_cli-0.18.2/src/acumatica_cli/templates/config/master/61-ap-preferences.yaml +0 -5
- acumatica_cli-0.18.2/src/acumatica_cli/templates/env +0 -16
- acumatica_cli-0.18.2/src/acumatica_cli/templates/target +0 -7
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/__init__.py +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/bootstrap_plugin.cs +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/firstlogin.py +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/models.py +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/output.py +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/10-subaccounts.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/40-ledger.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/60-ledger-company.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/baseline/90-uoms.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/bootstrap/company.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/bootstrap/credit-terms.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/bootstrap/features.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/10-reason-codes.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/30-availability-rules.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/40-posting-classes.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/50-warehouse.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/51-warehouse-locations.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/52-warehouse-defaults.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/53-tax-categories.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/54-item-classes.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/58-order-types.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/63-cash-account.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/64-payment-methods.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/65-statement-cycles.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/70-vendor-classes.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/71-customer-classes.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/75-vendors.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/76-customers.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/80-stock-items-parts.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/82-stock-items-kits.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/master/85-kit-specifications.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/setup/10-financial-year.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/setup/20-master-calendar.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/setup/30-open-periods.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/config/views/10-trial-balance.yaml +0 -0
- {acumatica_cli-0.18.2 → acumatica_cli-0.25.2}/src/acumatica_cli/templates/gitignore +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: acumatica-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.2
|
|
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>
|
|
@@ -39,21 +39,21 @@ uv tool install acumatica-cli
|
|
|
39
39
|
|
|
40
40
|
acu config init --host erp.example.com my-erp
|
|
41
41
|
cd my-erp # edit .env: set ACU_PASSWORD, ACU_TENANT
|
|
42
|
-
#
|
|
42
|
+
# pin+where = matrix.yaml cell (default_api + base_url)
|
|
43
43
|
# start from a brand-new empty tenant
|
|
44
44
|
|
|
45
|
-
acu config check # read-only preflight (incl.
|
|
46
|
-
acu tenant create --
|
|
45
|
+
acu config check # read-only preflight (incl. matrix.yaml)
|
|
46
|
+
acu tenant create --login DEV # create + bootstrap (SSH; --id optional)
|
|
47
47
|
# or hosted: acu --tenant DEV bootstrap
|
|
48
48
|
acu --tenant DEV apply config/ # seed config/{bootstrap,baseline,setup,master}/
|
|
49
49
|
acu --tenant DEV run scenario/ # once capital → buy → build → sell
|
|
50
50
|
acu --tenant DEV diff config/ # prove zero drift (exit 2 on drift)
|
|
51
51
|
acu --tenant DEV state # capture state/ trial-balance
|
|
52
|
-
acu --tenant DEV
|
|
52
|
+
acu check --yes --tenant DEV # cold lifecycle create→apply→run→diff (leave tenant)
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Bare `apply` / `diff` (no path args) also prefer `config/` when those trees exist.
|
|
56
|
-
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard,
|
|
56
|
+
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard, apply-order notes, NumberingSequence vs prefs `*NumberingID`, curated *Preferences field depth (V41), and Role/User + password seed rules.
|
|
57
57
|
|
|
58
58
|
**Hosted Acumatica (no SSH):** the tenant already exists; set a blank `ACU_SSH=` in `.env` (scaffold omits the key — without it, acu defaults to `Administrator@<ACU_BASE_URL host>` for SSH boxes).
|
|
59
59
|
|
|
@@ -71,19 +71,23 @@ acu bootstrap --export AcuBootstrap.zip # import + publish on SM204505
|
|
|
71
71
|
## CLI map
|
|
72
72
|
|
|
73
73
|
```text
|
|
74
|
-
acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
74
|
+
acu [--cell ID] [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
75
75
|
[--username U] [--password P] [--version] [--completion [SHELL]]
|
|
76
76
|
│
|
|
77
77
|
├── tenant tenant CRUD (ac.exe over SSH — control plane)
|
|
78
78
|
│ ├── list CompanyID, sign-in name, internal CD, type
|
|
79
|
-
│ ├── create --
|
|
79
|
+
│ ├── create --login NAME [--id N] create + bootstrap; re-run to republish (SSH)
|
|
80
80
|
│ │ [--type SalesDemo|T100|U100] [--parent N] [--hidden] [--no-init]
|
|
81
|
-
│
|
|
81
|
+
│ │ omit --id → next free CompanyID (max list + 1)
|
|
82
|
+
│ ├── delete --id N | --login NAME [--yes]
|
|
83
|
+
│ │ delete the tenant and its data, recycle app pool
|
|
84
|
+
│ └── recycle [--yes] restart site app pool (tenant map + free API slots)
|
|
82
85
|
│
|
|
83
86
|
├── bootstrap [--export PATH] publish AcuBootstrap (REST); --export = offline zip
|
|
84
87
|
├── apply [--dry-run] [FILES...] push YAML via REST (idempotent PUT upserts)
|
|
85
88
|
├── diff [FILES...] drift check vs the live tenant (exit 2 on drift)
|
|
86
89
|
├── run [--dry-run] [FILES...] execute transaction scenario YAML (exit 1 on any miss)
|
|
90
|
+
├── check [--all] [--yes] [--tenant L] cold lifecycle create→apply→run→diff; leave tenant (V47)
|
|
87
91
|
├── state [--out DIR] [--diff] [--assert-unchanged] [--dry-run] [FILES...]
|
|
88
92
|
│ capture derived state into state/ (not seed)
|
|
89
93
|
├── extract [--out DIR] [--only NAME]... [--force] [--dry-run]
|
|
@@ -95,14 +99,14 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
95
99
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
96
100
|
│
|
|
97
101
|
└── config configuration ops
|
|
98
|
-
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/,
|
|
102
|
+
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/, matrix.yaml)
|
|
99
103
|
├── show print the resolved config as a complete .env
|
|
100
|
-
└── check [--strict] preflight: discovery, secrets,
|
|
104
|
+
└── check [--strict] preflight: discovery, secrets, matrix, REST, endpoints, SSH
|
|
101
105
|
```
|
|
102
106
|
|
|
103
107
|
`apply` and `diff` without FILES prefer `config/<name>/` when any seed child exists under `config/`; otherwise root `bootstrap/`, `baseline/`, `setup/`, then `master/` when present.
|
|
104
108
|
A path like `config/` expands nested seed dirs in that fixed order.
|
|
105
|
-
`run` without FILES defaults to `scenario/`.
|
|
109
|
+
`run` without FILES defaults to `scenario/`. Scenario YAML may use `${current_period}` (host-local `MMyyyy`) on steps, expect params, and once.present params; `config/views` / `state` keep Period pinned (see [docs/demo-seed.md](docs/demo-seed.md#period-token-current_period-vs-pinned-views)).
|
|
106
110
|
`state` without FILES defaults to `config/views/`; writes go to `state/` (`--out`).
|
|
107
111
|
`extract` always writes under `config/{bootstrap,baseline,setup,master}/` (catalog-driven; never root SEED_DIRS).
|
|
108
112
|
`inventory` is offline (no REST/SSH/password): SM203520 Settings XML ZIP or `ac.exe export xml` folder writes to `inventory/`.
|
|
@@ -110,7 +114,9 @@ A path like `config/` expands nested seed dirs in that fixed order.
|
|
|
110
114
|
Optional `snapshot_map.yaml` (data-repo root or package defaults) maps DAC tables to catalog entities and normalizes join (pad-trim, key/field aliases, Account/Sub FK CD resolve, enum label to code).
|
|
111
115
|
See [docs/demo-seed.md](docs/demo-seed.md).
|
|
112
116
|
`acu --completion` emits a completion script for bash, zsh, or fish — source it from your shell profile.
|
|
113
|
-
Run `acu
|
|
117
|
+
Run `acu --help` for the full mental model (workflow, planes, exit codes,
|
|
118
|
+
command map) — enough for an agent to learn the tool without extra docs.
|
|
119
|
+
Run `acu <command> --help` (or `-h`) for flags, examples, and prerequisites.
|
|
114
120
|
|
|
115
121
|
### Dual readers, one writer
|
|
116
122
|
|
|
@@ -132,27 +138,28 @@ See [docs/ac-exe.md](docs/ac-exe.md) for export / SM203520 notes and [docs/demo-
|
|
|
132
138
|
## The data repo
|
|
133
139
|
|
|
134
140
|
Your configuration lives in its own git repo.
|
|
135
|
-
`acu config init` scaffolds a **single full seed** under `config/` (
|
|
141
|
+
`acu config init` scaffolds a **single full seed** under `config/` (features, company, credit terms, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README.
|
|
142
|
+
The Bootstrap endpoint contract is package SoT (`bootstrap_project.xml` inside the CLI — `Bootstrap/1.4.0`); `config init` never writes `project.xml`, and data repos must not keep one (a present file hard-errors on bootstrap/publish).
|
|
136
143
|
There is no `--flavor`.
|
|
137
144
|
|
|
138
145
|
| Path | What it holds |
|
|
139
146
|
| ---- | ------------- |
|
|
140
|
-
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms
|
|
147
|
+
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms (no `project.xml`) |
|
|
141
148
|
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs |
|
|
142
149
|
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
143
|
-
| `config/master/` | inventory/distribution masters (prefs, warehouse, items, parties) |
|
|
150
|
+
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users`) |
|
|
144
151
|
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
145
152
|
| `config/views/` | observer views for `acu state` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
146
153
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
147
154
|
| `inventory/` | engagement: offline snapshot tables from `acu inventory` (not seed; not SEED_DIRS) |
|
|
148
155
|
| `findings/` | engagement: `acu reconcile` cross-check output (never apply path) |
|
|
149
|
-
| `
|
|
150
|
-
| `.env` |
|
|
156
|
+
| `matrix.yaml` | multi-host pin+where: cells `id`+`erp`+`default_api`+`base_url` (V27); `--cell` selects |
|
|
157
|
+
| `.env` | secrets + optional where override (`ACU_*`); never Default API pin |
|
|
151
158
|
|
|
152
159
|
Legacy data repos may still keep root `bootstrap/`…`master/`; bare `apply`/`diff` prefer `config/` when present and never merge both trees.
|
|
153
160
|
|
|
154
161
|
Files in each directory apply alphabetically; the numbered prefixes (`10-`, `20-`, and so on) encode dependency order.
|
|
155
|
-
Commit `
|
|
162
|
+
Commit `matrix.yaml` with the seeds so every clone knows verified ERP line, Default API half, and REST where per cell.
|
|
156
163
|
|
|
157
164
|
Seed YAML is state: `apply` upserts it, `diff` proves it.
|
|
158
165
|
`acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut).
|
|
@@ -173,11 +180,12 @@ Dual-served entities (on both Bootstrap and Default) need an explicit `endpoint:
|
|
|
173
180
|
| Value | Resolves to |
|
|
174
181
|
| ----- | ----------- |
|
|
175
182
|
| omitted | `Default/<api_version>` for Default-only entities |
|
|
176
|
-
| `bootstrap` | active `Bootstrap/<ver>` from
|
|
183
|
+
| `bootstrap` | active `Bootstrap/<ver>` from the packaged contract only |
|
|
177
184
|
| `default` | `Default/<api_version>` — tracks the resolved API version |
|
|
178
|
-
| `Bootstrap/1.
|
|
185
|
+
| `Bootstrap/1.4.0` or `Default/25.200.001` | literal pin (ignores the resolved Default version) |
|
|
179
186
|
|
|
180
|
-
`api_version` resolves as `--api-version` flag, else `
|
|
187
|
+
`api_version` resolves as `--api-version` flag, else active `matrix.yaml` cell `default_api`, else code default `25.200.001` (never `ACU_API_VERSION` in `.env`).
|
|
188
|
+
`base_url` resolves as `--url`, else `ACU_BASE_URL`, else active cell `base_url`.
|
|
181
189
|
Prefer symbolic `default` over a pinned `Default/25.200.001` so the seed tree travels with the dataset pin.
|
|
182
190
|
|
|
183
191
|
## Installation
|
|
@@ -189,25 +197,27 @@ uv tool install acumatica-cli
|
|
|
189
197
|
```
|
|
190
198
|
|
|
191
199
|
`pipx install acumatica-cli` and `pip install acumatica-cli` work too.
|
|
192
|
-
|
|
200
|
+
|
|
201
|
+
Or clone and install editable for development:
|
|
193
202
|
|
|
194
203
|
```sh
|
|
195
|
-
|
|
204
|
+
git clone https://github.com/kborovik/acumatica-cli.git
|
|
205
|
+
cd acumatica-cli
|
|
206
|
+
gmake install # editable install as a global uv tool
|
|
196
207
|
```
|
|
197
208
|
|
|
198
209
|
Verify with `acu --version`.
|
|
199
210
|
|
|
200
211
|
## Configuration
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
(`
|
|
204
|
-
|
|
205
|
-
lives in committed `target.yaml` (`default_api`).
|
|
213
|
+
Secrets live in one `.env` file (`ACU_*` vars). Non-secret **where** and the
|
|
214
|
+
Default contract pin live in committed `matrix.yaml` (cell `base_url` +
|
|
215
|
+
`default_api`). Optional `ACU_BASE_URL` overrides cell where for ad-hoc probes.
|
|
206
216
|
|
|
207
217
|
```sh
|
|
208
|
-
ACU_BASE_URL
|
|
218
|
+
# ACU_BASE_URL optional when matrix.yaml cell carries base_url
|
|
209
219
|
ACU_TENANT=LAB5 # sign-in name of the tenant API sessions use
|
|
210
|
-
# ACU_SSH omitted → defaults to Administrator@
|
|
220
|
+
# ACU_SSH omitted → defaults to Administrator@ + resolved base_url host
|
|
211
221
|
# ACU_SSH= # hosted opt-out (blank key)
|
|
212
222
|
ACU_USER=admin # optional, defaults to admin
|
|
213
223
|
ACU_PASSWORD=... # required for live commands
|
|
@@ -217,34 +227,80 @@ There is no `ACU_API_VERSION` env key (unknown `ACU_*` vars are ignored).
|
|
|
217
227
|
Ad-hoc override: `acu --api-version 24.200.001 …` (version half only, never
|
|
218
228
|
`Default/25.200.001` — a full path would nest as `/entity/Default/Default/...`).
|
|
219
229
|
|
|
220
|
-
|
|
230
|
+
Committed `matrix.yaml` is the **sole data-repo pin+where registry** (1..N cells):
|
|
221
231
|
|
|
222
232
|
```yaml
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
cells:
|
|
234
|
+
- id: "default"
|
|
235
|
+
erp: "26.101.0225" # claimed product line/build
|
|
236
|
+
default_api: "25.200.001" # sources Instance.api_version when --api-version absent
|
|
237
|
+
base_url: "http://acu-dev1.vm.internal/AcumaticaERP"
|
|
225
238
|
```
|
|
226
239
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
`
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
`--cell <id>` selects a cell (omit means first cell).
|
|
241
|
+
When present, live commands source `api_version` from cell `default_api` and
|
|
242
|
+
`base_url` from the cell when flag/env leave them unset.
|
|
243
|
+
`acu config check` reports `ok matrix (cell=...; api_version from default_api=...; ...)`.
|
|
244
|
+
Missing `matrix.yaml` only warns on `config check` unless you pass `--strict`.
|
|
245
|
+
`acu check` (lifecycle) **requires** matrix.
|
|
246
|
+
|
|
247
|
+
### Multi-host matrix (V44)
|
|
248
|
+
|
|
249
|
+
One **trunk seed** in the data repo serves every host. Version fan-out is
|
|
250
|
+
**not** long-running product branches (`acu-25r1`, `acu-26r1`, …).
|
|
251
|
+
|
|
252
|
+
| Piece | Role |
|
|
253
|
+
| ----- | ---- |
|
|
254
|
+
| Trunk seed | Canonical `config/` + `scenario/` (newest supported matrix) |
|
|
255
|
+
| `matrix.yaml` cells | Each host: `id`+`erp`+`default_api`+`base_url`; `--cell` / `acu check --all` |
|
|
256
|
+
| Optional overlays | Surgical seed deltas keyed by Default half (e.g. `overlays/default-24.200.001/`) |
|
|
257
|
+
| OpenAPI | Live `acu schema` dump only (gitignored); never multi-version swagger trees in package or data repo |
|
|
258
|
+
|
|
259
|
+
**Overlays** live under `overlays/default-<default_api>/` (scaffolded by
|
|
260
|
+
`acu config init`). No `--overlay` flag.
|
|
261
|
+
|
|
262
|
+
**Bare compose (pin auto):** when path args are omitted, `acu apply` /
|
|
263
|
+
`acu diff` append overlay config seed dirs when present; `acu run` replaces
|
|
264
|
+
same-basename scenario files from the pin overlay. Pin =
|
|
265
|
+
resolved `api_version` (matrix cell `default_api`). Explicit path args
|
|
266
|
+
disable auto-compose.
|
|
267
|
+
|
|
268
|
+
```sh
|
|
269
|
+
# matrix cell default_api: 24.200.001 → uses overlays/default-24.200.001/
|
|
270
|
+
acu --cell lab25 apply
|
|
271
|
+
acu --cell lab25 run
|
|
272
|
+
acu --cell lab25 diff
|
|
273
|
+
|
|
274
|
+
# explicit path args (no auto) — later path wins same keys
|
|
275
|
+
acu apply config/ overlays/default-24.200.001/
|
|
276
|
+
acu diff config/ overlays/default-24.200.001/
|
|
277
|
+
|
|
278
|
+
# cold lifecycle every cell (SSH + tenant required); tenants left for inspect
|
|
279
|
+
acu check --all --yes --tenant LAB5
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Add a future half by creating `overlays/default-<new-half>/` with the
|
|
283
|
+
minimal rewrite; no long-running product branches and no multi-version
|
|
284
|
+
OpenAPI trees (V11/V44).
|
|
285
|
+
|
|
286
|
+
Sibling data-repo retirement of release branches:
|
|
287
|
+
[acumatica-gitops#2](https://github.com/kborovik/acumatica-gitops/issues/2).
|
|
232
288
|
|
|
233
289
|
Worth knowing:
|
|
234
290
|
|
|
235
|
-
- The file is found by walking up from the current directory, so any subdirectory of the data repo works.
|
|
236
|
-
- Without a `.env`, global flags plus the process environment supply the
|
|
237
|
-
- When `ACU_SSH` is **absent**, acu defaults to `Administrator@` + the
|
|
291
|
+
- The `.env` file is found by walking up from the current directory, so any subdirectory of the data repo works.
|
|
292
|
+
- Without a `.env`, global flags plus the process environment (and matrix cell where) supply the configuration.
|
|
293
|
+
- When `ACU_SSH` is **absent**, acu defaults to `Administrator@` + the resolved base_url hostname.
|
|
238
294
|
A **present blank** `ACU_SSH=` is the hosted opt-out.
|
|
239
|
-
Only `acu tenant`
|
|
240
|
-
- `acu config show` prints the resolved `.env` (password excluded; never `ACU_API_VERSION`) and comments
|
|
295
|
+
Only `acu tenant` / `acu check` require a non-empty value post-default.
|
|
296
|
+
- `acu config show` prints the resolved `.env` (password excluded; never `ACU_API_VERSION`) and comments active cell id/erp/default_api/base_url plus api_version source when `matrix.yaml` is present.
|
|
241
297
|
- Redirect it to turn resolved state into a working config: `acu config show > .env`.
|
|
242
298
|
|
|
243
299
|
Verify before touching anything live:
|
|
244
300
|
|
|
245
301
|
```sh
|
|
246
|
-
acu config check # discovery, secrets,
|
|
247
|
-
acu config check --strict # missing
|
|
302
|
+
acu config check # discovery, secrets, matrix, REST, endpoints, SSH
|
|
303
|
+
acu config check --strict # missing matrix.yaml becomes fail
|
|
248
304
|
acu apply --dry-run # show what would be written, write nothing
|
|
249
305
|
```
|
|
250
306
|
|
|
@@ -268,12 +324,23 @@ GitHub Actions runs the same gate on every push and pull request to `main`.
|
|
|
268
324
|
|
|
269
325
|
### Release
|
|
270
326
|
|
|
327
|
+
Human release notes live in root [`CHANGELOG.md`](CHANGELOG.md) (Keep a Changelog).
|
|
328
|
+
During development, append user-facing work under `## Unreleased` in `### Added` / `### Changed` / `### Fixed` as appropriate.
|
|
329
|
+
Empty Unreleased (no bullets) hard-fails the release — nothing to ship.
|
|
330
|
+
|
|
271
331
|
```sh
|
|
272
332
|
gmake release patch # or minor | major
|
|
273
333
|
```
|
|
274
334
|
|
|
275
|
-
|
|
276
|
-
|
|
335
|
+
`gmake release` is the sole release path (never local `gh release create`):
|
|
336
|
+
|
|
337
|
+
1. `gmake check` (ruff, basedpyright, offline pytest)
|
|
338
|
+
2. Fail if `## Unreleased` has no bullets
|
|
339
|
+
3. Bump `pyproject.toml` version (`major` | `minor` | `patch`)
|
|
340
|
+
4. Promote Unreleased body to `## [vX.Y.Z] - YYYY-MM-DD`, leave an empty `## Unreleased`
|
|
341
|
+
5. Commit `CHANGELOG.md` + `pyproject.toml` (+ lock if bumped) together, tag `vX.Y.Z`, push
|
|
342
|
+
|
|
343
|
+
GitHub Actions on tag `v*` re-runs CI, builds sdist+wheel, publishes to PyPI via OIDC trusted publishing, and creates a GitHub Release whose notes are the promoted CHANGELOG section for that tag (plus the artifacts).
|
|
277
344
|
|
|
278
345
|
### Live end-to-end tier
|
|
279
346
|
|
|
@@ -21,21 +21,21 @@ uv tool install acumatica-cli
|
|
|
21
21
|
|
|
22
22
|
acu config init --host erp.example.com my-erp
|
|
23
23
|
cd my-erp # edit .env: set ACU_PASSWORD, ACU_TENANT
|
|
24
|
-
#
|
|
24
|
+
# pin+where = matrix.yaml cell (default_api + base_url)
|
|
25
25
|
# start from a brand-new empty tenant
|
|
26
26
|
|
|
27
|
-
acu config check # read-only preflight (incl.
|
|
28
|
-
acu tenant create --
|
|
27
|
+
acu config check # read-only preflight (incl. matrix.yaml)
|
|
28
|
+
acu tenant create --login DEV # create + bootstrap (SSH; --id optional)
|
|
29
29
|
# or hosted: acu --tenant DEV bootstrap
|
|
30
30
|
acu --tenant DEV apply config/ # seed config/{bootstrap,baseline,setup,master}/
|
|
31
31
|
acu --tenant DEV run scenario/ # once capital → buy → build → sell
|
|
32
32
|
acu --tenant DEV diff config/ # prove zero drift (exit 2 on drift)
|
|
33
33
|
acu --tenant DEV state # capture state/ trial-balance
|
|
34
|
-
acu --tenant DEV
|
|
34
|
+
acu check --yes --tenant DEV # cold lifecycle create→apply→run→diff (leave tenant)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Bare `apply` / `diff` (no path args) also prefer `config/` when those trees exist.
|
|
38
|
-
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard,
|
|
38
|
+
See [docs/demo-seed.md](docs/demo-seed.md) for the entity map, once-guard, apply-order notes, NumberingSequence vs prefs `*NumberingID`, curated *Preferences field depth (V41), and Role/User + password seed rules.
|
|
39
39
|
|
|
40
40
|
**Hosted Acumatica (no SSH):** the tenant already exists; set a blank `ACU_SSH=` in `.env` (scaffold omits the key — without it, acu defaults to `Administrator@<ACU_BASE_URL host>` for SSH boxes).
|
|
41
41
|
|
|
@@ -53,19 +53,23 @@ acu bootstrap --export AcuBootstrap.zip # import + publish on SM204505
|
|
|
53
53
|
## CLI map
|
|
54
54
|
|
|
55
55
|
```text
|
|
56
|
-
acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
56
|
+
acu [--cell ID] [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
57
57
|
[--username U] [--password P] [--version] [--completion [SHELL]]
|
|
58
58
|
│
|
|
59
59
|
├── tenant tenant CRUD (ac.exe over SSH — control plane)
|
|
60
60
|
│ ├── list CompanyID, sign-in name, internal CD, type
|
|
61
|
-
│ ├── create --
|
|
61
|
+
│ ├── create --login NAME [--id N] create + bootstrap; re-run to republish (SSH)
|
|
62
62
|
│ │ [--type SalesDemo|T100|U100] [--parent N] [--hidden] [--no-init]
|
|
63
|
-
│
|
|
63
|
+
│ │ omit --id → next free CompanyID (max list + 1)
|
|
64
|
+
│ ├── delete --id N | --login NAME [--yes]
|
|
65
|
+
│ │ delete the tenant and its data, recycle app pool
|
|
66
|
+
│ └── recycle [--yes] restart site app pool (tenant map + free API slots)
|
|
64
67
|
│
|
|
65
68
|
├── bootstrap [--export PATH] publish AcuBootstrap (REST); --export = offline zip
|
|
66
69
|
├── apply [--dry-run] [FILES...] push YAML via REST (idempotent PUT upserts)
|
|
67
70
|
├── diff [FILES...] drift check vs the live tenant (exit 2 on drift)
|
|
68
71
|
├── run [--dry-run] [FILES...] execute transaction scenario YAML (exit 1 on any miss)
|
|
72
|
+
├── check [--all] [--yes] [--tenant L] cold lifecycle create→apply→run→diff; leave tenant (V47)
|
|
69
73
|
├── state [--out DIR] [--diff] [--assert-unchanged] [--dry-run] [FILES...]
|
|
70
74
|
│ capture derived state into state/ (not seed)
|
|
71
75
|
├── extract [--out DIR] [--only NAME]... [--force] [--dry-run]
|
|
@@ -77,14 +81,14 @@ acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--api-version V]
|
|
|
77
81
|
├── schema [--out DIR] dump the endpoint's OpenAPI schema (swagger.json)
|
|
78
82
|
│
|
|
79
83
|
└── config configuration ops
|
|
80
|
-
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/,
|
|
84
|
+
├── init [--host HOST] [DIR] scaffold full data repo (config/, scenario/, matrix.yaml)
|
|
81
85
|
├── show print the resolved config as a complete .env
|
|
82
|
-
└── check [--strict] preflight: discovery, secrets,
|
|
86
|
+
└── check [--strict] preflight: discovery, secrets, matrix, REST, endpoints, SSH
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
`apply` and `diff` without FILES prefer `config/<name>/` when any seed child exists under `config/`; otherwise root `bootstrap/`, `baseline/`, `setup/`, then `master/` when present.
|
|
86
90
|
A path like `config/` expands nested seed dirs in that fixed order.
|
|
87
|
-
`run` without FILES defaults to `scenario/`.
|
|
91
|
+
`run` without FILES defaults to `scenario/`. Scenario YAML may use `${current_period}` (host-local `MMyyyy`) on steps, expect params, and once.present params; `config/views` / `state` keep Period pinned (see [docs/demo-seed.md](docs/demo-seed.md#period-token-current_period-vs-pinned-views)).
|
|
88
92
|
`state` without FILES defaults to `config/views/`; writes go to `state/` (`--out`).
|
|
89
93
|
`extract` always writes under `config/{bootstrap,baseline,setup,master}/` (catalog-driven; never root SEED_DIRS).
|
|
90
94
|
`inventory` is offline (no REST/SSH/password): SM203520 Settings XML ZIP or `ac.exe export xml` folder writes to `inventory/`.
|
|
@@ -92,7 +96,9 @@ A path like `config/` expands nested seed dirs in that fixed order.
|
|
|
92
96
|
Optional `snapshot_map.yaml` (data-repo root or package defaults) maps DAC tables to catalog entities and normalizes join (pad-trim, key/field aliases, Account/Sub FK CD resolve, enum label to code).
|
|
93
97
|
See [docs/demo-seed.md](docs/demo-seed.md).
|
|
94
98
|
`acu --completion` emits a completion script for bash, zsh, or fish — source it from your shell profile.
|
|
95
|
-
Run `acu
|
|
99
|
+
Run `acu --help` for the full mental model (workflow, planes, exit codes,
|
|
100
|
+
command map) — enough for an agent to learn the tool without extra docs.
|
|
101
|
+
Run `acu <command> --help` (or `-h`) for flags, examples, and prerequisites.
|
|
96
102
|
|
|
97
103
|
### Dual readers, one writer
|
|
98
104
|
|
|
@@ -114,27 +120,28 @@ See [docs/ac-exe.md](docs/ac-exe.md) for export / SM203520 notes and [docs/demo-
|
|
|
114
120
|
## The data repo
|
|
115
121
|
|
|
116
122
|
Your configuration lives in its own git repo.
|
|
117
|
-
`acu config init` scaffolds a **single full seed** under `config/` (
|
|
123
|
+
`acu config init` scaffolds a **single full seed** under `config/` (features, company, credit terms, expanded COA, masters) plus lifecycle `scenario/`, observer `config/views/`, and README.
|
|
124
|
+
The Bootstrap endpoint contract is package SoT (`bootstrap_project.xml` inside the CLI — `Bootstrap/1.4.0`); `config init` never writes `project.xml`, and data repos must not keep one (a present file hard-errors on bootstrap/publish).
|
|
118
125
|
There is no `--flavor`.
|
|
119
126
|
|
|
120
127
|
| Path | What it holds |
|
|
121
128
|
| ---- | ------------- |
|
|
122
|
-
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms
|
|
129
|
+
| `config/bootstrap/` | virgin-tenant config: features, company, credit terms (no `project.xml`) |
|
|
123
130
|
| `config/baseline/` | reference data: subaccounts, COA, ledger, UOMs |
|
|
124
131
|
| `config/setup/` | one-time actions: financial year, master calendar, open periods |
|
|
125
|
-
| `config/master/` | inventory/distribution masters (prefs, warehouse, items, parties) |
|
|
132
|
+
| `config/master/` | inventory/distribution masters: numbering (`05-…`) before prefs, warehouse, items, parties + Role/User (`90-roles` then `91-users`) |
|
|
126
133
|
| `scenario/` | lifecycle txns for `acu run`: once capital, then buy, build, sell |
|
|
127
134
|
| `config/views/` | observer views for `acu state` (`inquire:` / `entity:` / `gi:`; not SEED_DIRS) |
|
|
128
135
|
| `state/` | committed derived-state observations (evidence, not seed; money/qty fixed-point) |
|
|
129
136
|
| `inventory/` | engagement: offline snapshot tables from `acu inventory` (not seed; not SEED_DIRS) |
|
|
130
137
|
| `findings/` | engagement: `acu reconcile` cross-check output (never apply path) |
|
|
131
|
-
| `
|
|
132
|
-
| `.env` |
|
|
138
|
+
| `matrix.yaml` | multi-host pin+where: cells `id`+`erp`+`default_api`+`base_url` (V27); `--cell` selects |
|
|
139
|
+
| `.env` | secrets + optional where override (`ACU_*`); never Default API pin |
|
|
133
140
|
|
|
134
141
|
Legacy data repos may still keep root `bootstrap/`…`master/`; bare `apply`/`diff` prefer `config/` when present and never merge both trees.
|
|
135
142
|
|
|
136
143
|
Files in each directory apply alphabetically; the numbered prefixes (`10-`, `20-`, and so on) encode dependency order.
|
|
137
|
-
Commit `
|
|
144
|
+
Commit `matrix.yaml` with the seeds so every clone knows verified ERP line, Default API half, and REST where per cell.
|
|
138
145
|
|
|
139
146
|
Seed YAML is state: `apply` upserts it, `diff` proves it.
|
|
140
147
|
`acu extract` is the inverse of `apply`: GET live tenant rows into seed YAML under `config/{bootstrap,baseline,setup,master}/` (hard-cut).
|
|
@@ -155,11 +162,12 @@ Dual-served entities (on both Bootstrap and Default) need an explicit `endpoint:
|
|
|
155
162
|
| Value | Resolves to |
|
|
156
163
|
| ----- | ----------- |
|
|
157
164
|
| omitted | `Default/<api_version>` for Default-only entities |
|
|
158
|
-
| `bootstrap` | active `Bootstrap/<ver>` from
|
|
165
|
+
| `bootstrap` | active `Bootstrap/<ver>` from the packaged contract only |
|
|
159
166
|
| `default` | `Default/<api_version>` — tracks the resolved API version |
|
|
160
|
-
| `Bootstrap/1.
|
|
167
|
+
| `Bootstrap/1.4.0` or `Default/25.200.001` | literal pin (ignores the resolved Default version) |
|
|
161
168
|
|
|
162
|
-
`api_version` resolves as `--api-version` flag, else `
|
|
169
|
+
`api_version` resolves as `--api-version` flag, else active `matrix.yaml` cell `default_api`, else code default `25.200.001` (never `ACU_API_VERSION` in `.env`).
|
|
170
|
+
`base_url` resolves as `--url`, else `ACU_BASE_URL`, else active cell `base_url`.
|
|
163
171
|
Prefer symbolic `default` over a pinned `Default/25.200.001` so the seed tree travels with the dataset pin.
|
|
164
172
|
|
|
165
173
|
## Installation
|
|
@@ -171,25 +179,27 @@ uv tool install acumatica-cli
|
|
|
171
179
|
```
|
|
172
180
|
|
|
173
181
|
`pipx install acumatica-cli` and `pip install acumatica-cli` work too.
|
|
174
|
-
|
|
182
|
+
|
|
183
|
+
Or clone and install editable for development:
|
|
175
184
|
|
|
176
185
|
```sh
|
|
177
|
-
|
|
186
|
+
git clone https://github.com/kborovik/acumatica-cli.git
|
|
187
|
+
cd acumatica-cli
|
|
188
|
+
gmake install # editable install as a global uv tool
|
|
178
189
|
```
|
|
179
190
|
|
|
180
191
|
Verify with `acu --version`.
|
|
181
192
|
|
|
182
193
|
## Configuration
|
|
183
194
|
|
|
184
|
-
|
|
185
|
-
(`
|
|
186
|
-
|
|
187
|
-
lives in committed `target.yaml` (`default_api`).
|
|
195
|
+
Secrets live in one `.env` file (`ACU_*` vars). Non-secret **where** and the
|
|
196
|
+
Default contract pin live in committed `matrix.yaml` (cell `base_url` +
|
|
197
|
+
`default_api`). Optional `ACU_BASE_URL` overrides cell where for ad-hoc probes.
|
|
188
198
|
|
|
189
199
|
```sh
|
|
190
|
-
ACU_BASE_URL
|
|
200
|
+
# ACU_BASE_URL optional when matrix.yaml cell carries base_url
|
|
191
201
|
ACU_TENANT=LAB5 # sign-in name of the tenant API sessions use
|
|
192
|
-
# ACU_SSH omitted → defaults to Administrator@
|
|
202
|
+
# ACU_SSH omitted → defaults to Administrator@ + resolved base_url host
|
|
193
203
|
# ACU_SSH= # hosted opt-out (blank key)
|
|
194
204
|
ACU_USER=admin # optional, defaults to admin
|
|
195
205
|
ACU_PASSWORD=... # required for live commands
|
|
@@ -199,34 +209,80 @@ There is no `ACU_API_VERSION` env key (unknown `ACU_*` vars are ignored).
|
|
|
199
209
|
Ad-hoc override: `acu --api-version 24.200.001 …` (version half only, never
|
|
200
210
|
`Default/25.200.001` — a full path would nest as `/entity/Default/Default/...`).
|
|
201
211
|
|
|
202
|
-
|
|
212
|
+
Committed `matrix.yaml` is the **sole data-repo pin+where registry** (1..N cells):
|
|
203
213
|
|
|
204
214
|
```yaml
|
|
205
|
-
|
|
206
|
-
|
|
215
|
+
cells:
|
|
216
|
+
- id: "default"
|
|
217
|
+
erp: "26.101.0225" # claimed product line/build
|
|
218
|
+
default_api: "25.200.001" # sources Instance.api_version when --api-version absent
|
|
219
|
+
base_url: "http://acu-dev1.vm.internal/AcumaticaERP"
|
|
207
220
|
```
|
|
208
221
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
`
|
|
212
|
-
|
|
213
|
-
|
|
222
|
+
`--cell <id>` selects a cell (omit means first cell).
|
|
223
|
+
When present, live commands source `api_version` from cell `default_api` and
|
|
224
|
+
`base_url` from the cell when flag/env leave them unset.
|
|
225
|
+
`acu config check` reports `ok matrix (cell=...; api_version from default_api=...; ...)`.
|
|
226
|
+
Missing `matrix.yaml` only warns on `config check` unless you pass `--strict`.
|
|
227
|
+
`acu check` (lifecycle) **requires** matrix.
|
|
228
|
+
|
|
229
|
+
### Multi-host matrix (V44)
|
|
230
|
+
|
|
231
|
+
One **trunk seed** in the data repo serves every host. Version fan-out is
|
|
232
|
+
**not** long-running product branches (`acu-25r1`, `acu-26r1`, …).
|
|
233
|
+
|
|
234
|
+
| Piece | Role |
|
|
235
|
+
| ----- | ---- |
|
|
236
|
+
| Trunk seed | Canonical `config/` + `scenario/` (newest supported matrix) |
|
|
237
|
+
| `matrix.yaml` cells | Each host: `id`+`erp`+`default_api`+`base_url`; `--cell` / `acu check --all` |
|
|
238
|
+
| Optional overlays | Surgical seed deltas keyed by Default half (e.g. `overlays/default-24.200.001/`) |
|
|
239
|
+
| OpenAPI | Live `acu schema` dump only (gitignored); never multi-version swagger trees in package or data repo |
|
|
240
|
+
|
|
241
|
+
**Overlays** live under `overlays/default-<default_api>/` (scaffolded by
|
|
242
|
+
`acu config init`). No `--overlay` flag.
|
|
243
|
+
|
|
244
|
+
**Bare compose (pin auto):** when path args are omitted, `acu apply` /
|
|
245
|
+
`acu diff` append overlay config seed dirs when present; `acu run` replaces
|
|
246
|
+
same-basename scenario files from the pin overlay. Pin =
|
|
247
|
+
resolved `api_version` (matrix cell `default_api`). Explicit path args
|
|
248
|
+
disable auto-compose.
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
# matrix cell default_api: 24.200.001 → uses overlays/default-24.200.001/
|
|
252
|
+
acu --cell lab25 apply
|
|
253
|
+
acu --cell lab25 run
|
|
254
|
+
acu --cell lab25 diff
|
|
255
|
+
|
|
256
|
+
# explicit path args (no auto) — later path wins same keys
|
|
257
|
+
acu apply config/ overlays/default-24.200.001/
|
|
258
|
+
acu diff config/ overlays/default-24.200.001/
|
|
259
|
+
|
|
260
|
+
# cold lifecycle every cell (SSH + tenant required); tenants left for inspect
|
|
261
|
+
acu check --all --yes --tenant LAB5
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Add a future half by creating `overlays/default-<new-half>/` with the
|
|
265
|
+
minimal rewrite; no long-running product branches and no multi-version
|
|
266
|
+
OpenAPI trees (V11/V44).
|
|
267
|
+
|
|
268
|
+
Sibling data-repo retirement of release branches:
|
|
269
|
+
[acumatica-gitops#2](https://github.com/kborovik/acumatica-gitops/issues/2).
|
|
214
270
|
|
|
215
271
|
Worth knowing:
|
|
216
272
|
|
|
217
|
-
- The file is found by walking up from the current directory, so any subdirectory of the data repo works.
|
|
218
|
-
- Without a `.env`, global flags plus the process environment supply the
|
|
219
|
-
- When `ACU_SSH` is **absent**, acu defaults to `Administrator@` + the
|
|
273
|
+
- The `.env` file is found by walking up from the current directory, so any subdirectory of the data repo works.
|
|
274
|
+
- Without a `.env`, global flags plus the process environment (and matrix cell where) supply the configuration.
|
|
275
|
+
- When `ACU_SSH` is **absent**, acu defaults to `Administrator@` + the resolved base_url hostname.
|
|
220
276
|
A **present blank** `ACU_SSH=` is the hosted opt-out.
|
|
221
|
-
Only `acu tenant`
|
|
222
|
-
- `acu config show` prints the resolved `.env` (password excluded; never `ACU_API_VERSION`) and comments
|
|
277
|
+
Only `acu tenant` / `acu check` require a non-empty value post-default.
|
|
278
|
+
- `acu config show` prints the resolved `.env` (password excluded; never `ACU_API_VERSION`) and comments active cell id/erp/default_api/base_url plus api_version source when `matrix.yaml` is present.
|
|
223
279
|
- Redirect it to turn resolved state into a working config: `acu config show > .env`.
|
|
224
280
|
|
|
225
281
|
Verify before touching anything live:
|
|
226
282
|
|
|
227
283
|
```sh
|
|
228
|
-
acu config check # discovery, secrets,
|
|
229
|
-
acu config check --strict # missing
|
|
284
|
+
acu config check # discovery, secrets, matrix, REST, endpoints, SSH
|
|
285
|
+
acu config check --strict # missing matrix.yaml becomes fail
|
|
230
286
|
acu apply --dry-run # show what would be written, write nothing
|
|
231
287
|
```
|
|
232
288
|
|
|
@@ -250,12 +306,23 @@ GitHub Actions runs the same gate on every push and pull request to `main`.
|
|
|
250
306
|
|
|
251
307
|
### Release
|
|
252
308
|
|
|
309
|
+
Human release notes live in root [`CHANGELOG.md`](CHANGELOG.md) (Keep a Changelog).
|
|
310
|
+
During development, append user-facing work under `## Unreleased` in `### Added` / `### Changed` / `### Fixed` as appropriate.
|
|
311
|
+
Empty Unreleased (no bullets) hard-fails the release — nothing to ship.
|
|
312
|
+
|
|
253
313
|
```sh
|
|
254
314
|
gmake release patch # or minor | major
|
|
255
315
|
```
|
|
256
316
|
|
|
257
|
-
|
|
258
|
-
|
|
317
|
+
`gmake release` is the sole release path (never local `gh release create`):
|
|
318
|
+
|
|
319
|
+
1. `gmake check` (ruff, basedpyright, offline pytest)
|
|
320
|
+
2. Fail if `## Unreleased` has no bullets
|
|
321
|
+
3. Bump `pyproject.toml` version (`major` | `minor` | `patch`)
|
|
322
|
+
4. Promote Unreleased body to `## [vX.Y.Z] - YYYY-MM-DD`, leave an empty `## Unreleased`
|
|
323
|
+
5. Commit `CHANGELOG.md` + `pyproject.toml` (+ lock if bumped) together, tag `vX.Y.Z`, push
|
|
324
|
+
|
|
325
|
+
GitHub Actions on tag `v*` re-runs CI, builds sdist+wheel, publishes to PyPI via OIDC trusted publishing, and creates a GitHub Release whose notes are the promoted CHANGELOG section for that tag (plus the artifacts).
|
|
259
326
|
|
|
260
327
|
### Live end-to-end tier
|
|
261
328
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "acumatica-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.25.2"
|
|
4
4
|
description = "Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data"
|
|
5
5
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
6
6
|
readme = "README.md"
|
|
@@ -32,6 +32,7 @@ build-backend = "uv_build"
|
|
|
32
32
|
[dependency-groups]
|
|
33
33
|
dev = [
|
|
34
34
|
"basedpyright>=1.37.0",
|
|
35
|
+
"freezegun>=1.5.5",
|
|
35
36
|
"pytest>=8",
|
|
36
37
|
"ruff>=0.13.0",
|
|
37
38
|
]
|
|
@@ -101,7 +102,11 @@ convention = "google"
|
|
|
101
102
|
known-first-party = ["acumatica_cli"]
|
|
102
103
|
|
|
103
104
|
[tool.ruff.lint.per-file-ignores]
|
|
104
|
-
"src/acumatica_cli/cli.py" = [
|
|
105
|
+
"src/acumatica_cli/cli.py" = [
|
|
106
|
+
"PLR0913",
|
|
107
|
+
"PLR0917",
|
|
108
|
+
"D301",
|
|
109
|
+
]
|
|
105
110
|
"tests/*" = [
|
|
106
111
|
"D101",
|
|
107
112
|
"D102",
|