Skip to content

Commit b9d4074

Browse files
Merge pull request #165 from cubewise-code/feat/issue-164-config-flag
feat(cli): add --config flag to override config.ini location (#164)
2 parents 5d5f6cf + 5cd76eb commit b9d4074

12 files changed

Lines changed: 376 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22

33
All notable changes to RushTI are documented in this file.
44

5-
## Unreleased — `feat/issue-156-chore-task-kind`
5+
## [Unreleased]
6+
7+
- **Added: `--config PATH` CLI flag** (closes #164). Overrides the location of
8+
`config.ini` (TM1 connection parameters) for a single invocation, on every
9+
TM1-connecting command (`run`, `build`, `tasks …`, `resume`). Precedence:
10+
`--config` > `RUSHTI_DIR` > legacy CWD > `config/`. The flag relocates only
11+
`config.ini``settings.ini` (`--settings`) and `logging_config.ini` keep
12+
their own resolution. A missing path fails fast (exit 1, no traceback). The
13+
resolved path is threaded explicitly into the TM1 connection layer rather
14+
than mutating a global. Enables sharing one read-only `config.ini` with other
15+
tm1py utilities. No behavioural change when the flag is absent. See
16+
`docs/adr/0003-config-ini-location-resolution.md`.
17+
18+
## [2.3.0] - 2026-06-17
619

720
- **Added: TM1 chore execution as a first-class task kind** (closes #156).
821
Mixed process + chore taskfiles are now supported across JSON, TXT, and
@@ -29,27 +42,32 @@ All notable changes to RushTI are documented in this file.
2942
- Dashboard: the per-task "Process" column is replaced by a unified
3043
"Task target" column with a `[P]` / `[C]` kind indicator so process
3144
and chore rows render side-by-side.
32-
33-
## Unreleased — docs: `--mode` for cube reads (#160)
34-
3545
- **Docs fix:** corrected the long-standing claim that `--mode` is
36-
deprecated/ignored. It is only auto-detected (and ignored) for **file
37-
sources** (`--tasks`). A **cube read** (`--tm1-instance`) cannot infer
38-
the mode — every workflow occupies the same cube measures — so it
46+
deprecated/ignored (#160). It is only auto-detected (and ignored) for
47+
**file sources** (`--tasks`). A **cube read** (`--tm1-instance`) cannot
48+
infer the mode — every workflow occupies the same cube measures — so it
3949
defaults to `norm` and silently drops the `predecessors` measure unless
4050
`--mode opt` is passed. This caused predecessors to disappear from
4151
cube-read execution plans (e.g. `Sample_Optimal_Mode`). Updated the CLI
4252
reference, settings reference, migration guide, TM1 integration guide
4353
(new "Choosing the mode for cube reads" section), getting-started
4454
task-files page, and the `rushti run --help` text.
4555

46-
## Unreleased — `feat/issue-154-v12-load-results`
56+
## [2.2.3] - 2026-06-01
57+
58+
- Fix: `TM1Service` kwarg collision when connection parameters are set in
59+
`config.ini` (#158).
60+
61+
## [2.2.2] - 2026-05-20
4762

4863
- Fix: `rushti build` now installs a TM1-version-aware `}rushti.load.results`
4964
TI (closes #154). On v12 targets the body no longer references the removed
5065
`CubeGetLogChanges` / `CubeSetLogChanges` / `ExecuteCommand` functions;
5166
source-file cleanup uses the TM1-native `ASCIIDelete` instead of shelling
5267
out via `cmd /c del`. The v11 body is unchanged.
68+
69+
## [2.2.1] - 2026-05-20
70+
5371
- **Per-workflow `tm1_instance` setting** for results push and auto-load.
5472
Set it inside a JSON taskfile's `settings` block to override the
5573
`settings.ini` default per workflow. Resolution chain (highest wins):
@@ -71,7 +89,7 @@ All notable changes to RushTI are documented in this file.
7189
`--tm1-instance` instead. The legacy flag is aliased and continues to
7290
work; a `DEPRECATION:` warning fires on use.
7391

74-
## Unreleased — `feat/issue-146-detailed-results`
92+
## [2.2.0] - 2026-05-18
7593

7694
- Add `--detailed-results` for per-execution cube rows (closes #146).
7795
- Log migration hint at run start when `--detailed-results` is enabled.

CONTEXT.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,34 @@ The effective value for a settings-driven knob is resolved in this order
118118

119119
Three knobs are *not* settings-driven and don't follow this chain:
120120
- Per-task `instance` and `process` — taskfile-only, no fallback.
121-
- TM1 connection parameters — `config.ini` only.
121+
- TM1 connection parameters — `config.ini` only (the *values*; the file's
122+
*location* is resolved separately, see below).
123+
124+
---
125+
126+
## config.ini location resolution
127+
128+
`config.ini` holds TM1 connection parameters only; its *location* is resolved
129+
by `resolve_config_path("config.ini", cli_path=…)` (`app_paths.py`) in this
130+
order (highest wins):
131+
132+
1. **`--config` CLI flag** — explicit path to a `config.ini` file. Present on
133+
every TM1-connecting command (`run`, `build`, `tasks …`, `resume`); not on
134+
`stats`/`db`, which touch only local SQLite + settings.ini. A missing path
135+
fails fast with a clean error, no traceback.
136+
2. **`RUSHTI_DIR` env var** — looks in `{RUSHTI_DIR}/config/config.ini`.
137+
3. **Legacy CWD**`./config.ini` (deprecated, warns once).
138+
4. **`config/config.ini`** — the recommended default location.
139+
140+
`--config` relocates **only `config.ini`** — settings.ini keeps `--settings`,
141+
logging_config.ini keeps its own resolution, and `RUSHTI_DIR` still governs
142+
those siblings. The flag exists so RushTI can share one read-only `config.ini`
143+
with other tm1py utilities (e.g. OptimusPy) instead of duplicating it. When
144+
`--config` is absent, resolution is unchanged from prior behaviour.
145+
146+
The resolved path is **threaded explicitly** as `config_path` into the TM1
147+
connection layer (`connect_to_tm1_instance`, `setup_tm1_services`); the
148+
module-level `CONFIG` global in `cli.py` is now only the no-flag default.
122149

123150
---
124151

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ user = admin
6565
password = apple
6666
```
6767

68+
RushTI looks for `config.ini` under `config/` (or `RUSHTI_DIR`). To point a
69+
single run at a different file — e.g. a `config.ini` shared with other tm1py
70+
utilities — pass `--config PATH` to any TM1-connecting command (`run`, `build`,
71+
`tasks`, `resume`).
72+
6873
**2. Create a task file**
6974

7075
```json

docs/advanced/cli-reference.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ rushti --tasks FILE [options] # 'run' is the default command
5555
| `--retries` | `-r` | INT | `0` | Retry count for failed TI executions. Uses exponential backoff. |
5656
| `--result` | `-o` | PATH | *(empty)* | Output CSV path for execution summary. Omit to skip CSV creation. |
5757
| `--settings` | `-s` | PATH | auto | Path to `settings.ini`. Auto-discovered if omitted. |
58+
| `--config` | | PATH | auto | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. Relocates **only** `config.ini`; `settings.ini` and `logging_config.ini` keep their own resolution. A missing path fails fast (exit 1, no traceback). |
5859
| `--mode` | `-m` | CHOICE | `norm` | Execution mode: `norm` or `opt`. **Ignored for file sources** (`--tasks`), where mode is auto-detected from file content. **Required for cube reads** (`--tm1-instance`) when the workflow uses explicit `predecessors` — pass `--mode opt`, otherwise the cube is read in `norm` mode and predecessors are dropped. See [TM1 integration → Choosing the mode for cube reads](../features/tm1-integration.md#choosing-the-mode-for-cube-reads). |
5960
| `--exclusive` | `-x` | FLAG | `false` | Enable exclusive mode. Waits for other RushTI sessions to finish. |
6061
| `--force` | `-f` | FLAG | `false` | Bypass exclusive mode checks and run immediately. |
@@ -123,6 +124,7 @@ rushti resume --tasks FILE [options] # auto-finds checkpoint
123124
| `--resume-from` | | STR | *(none)* | Resume from a specific task ID, overriding checkpoint state. |
124125
| `--max-workers` | `-w` | INT | *(from settings)* | Maximum parallel workers. |
125126
| `--settings` | `-s` | PATH | auto | Path to `settings.ini`. |
127+
| `--config` | | PATH | auto | Path to `config.ini` (TM1 connection parameters). Forwarded into the resumed run. |
126128
| `--force` | `-f` | FLAG | `false` | Force resume even if checkpoint does not match the current task file. |
127129
| `--log-level` | `-L` | CHOICE | `INFO` | Override log level. |
128130

@@ -164,6 +166,7 @@ rushti tasks export --tm1-instance tm1srv01 -W DailyETL --output daily.json
164166
| `--tm1-instance` | | STR | Read source from TM1 |
165167
| `--workflow` | `-W` | STR | Workflow in TM1 |
166168
| `--settings` | `-s` | PATH | Path to `settings.ini` |
169+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
167170

168171
---
169172

@@ -183,6 +186,7 @@ rushti tasks expand --tasks template.json --output expanded.json
183186
| `--tm1-instance` | | STR | TM1 source instance |
184187
| `--workflow` | `-W` | STR | Workflow in TM1 |
185188
| `--settings` | `-s` | PATH | Path to `settings.ini` |
189+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
186190

187191
---
188192

@@ -203,6 +207,7 @@ rushti tasks visualize --tasks daily-etl.json --output dag.html --show-parameter
203207
| `--tm1-instance` | | STR | TM1 source instance |
204208
| `--workflow` | `-W` | STR | Workflow in TM1 |
205209
| `--settings` | `-s` | PATH | Path to `settings.ini` |
210+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
206211

207212
---
208213

@@ -224,6 +229,7 @@ rushti tasks validate --tasks daily-etl.json --json > validation.json
224229
| `--tm1-instance` | | STR | TM1 source instance |
225230
| `--workflow` | `-W` | STR | Workflow in TM1 |
226231
| `--settings` | `-s` | PATH | Path to `settings.ini` |
232+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
227233

228234
---
229235

@@ -241,6 +247,7 @@ rushti tasks push --tasks daily-etl.json --tm1-instance tm1srv01
241247
| `--tm1-instance` | | STR | TM1 instance to push the taskfile to. Context disambiguates the role — on `tasks push` this is the destination. |
242248
| `--target-tm1-instance` | | STR | **Deprecated alias** for `--tm1-instance`. Still works; emits a `DEPRECATION:` warning when used. |
243249
| `--settings` | `-s` | PATH | Path to `settings.ini` |
250+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
244251

245252
---
246253

@@ -265,6 +272,7 @@ rushti stats list tasks --workflow daily-etl --limit 50
265272
| `--workflow` | `-W` | STR | Workflow (*required*) |
266273
| `--limit` | `-n` | INT | Maximum items to show (default: 20) |
267274
| `--settings` | `-s` | PATH | Path to `settings.ini` |
275+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
268276

269277
---
270278

@@ -283,6 +291,7 @@ rushti stats export --workflow daily-etl --run-id 20260115_103000 --output run.c
283291
| `--run-id` | `-r` | STR | Specific run ID to export (all runs if omitted) |
284292
| `--output` | `-o` | PATH | Output CSV file path (*required*) |
285293
| `--settings` | `-s` | PATH | Path to `settings.ini` |
294+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
286295

287296
---
288297

@@ -301,6 +310,7 @@ rushti stats visualize --workflow daily-etl --runs 10 --output dashboard.html
301310
| `--runs` | `-n` | INT | Number of recent runs to display (default: 5) |
302311
| `--output` | `-o` | PATH | Output HTML file path (default: `visualizations/rushti_dashboard_<id>.html`) |
303312
| `--settings` | `-s` | PATH | Path to `settings.ini` |
313+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
304314

305315
!!! info "DAG reflects the latest executed run"
306316
Both the dashboard and the DAG are sourced from the stats database — not from the live taskfile or TM1 cube definition. Editing a workflow definition without re-running it will not update either visualization. Re-run the workflow to refresh.
@@ -328,6 +338,7 @@ rushti stats analyze --workflow daily-etl --report report.json --ewma-alpha 0.5
328338
| `--runs` | `-n` | INT | Number of recent runs to analyze (default: 10) |
329339
| `--ewma-alpha` | | FLOAT | EWMA smoothing factor 0--1 (default: 0.3). Higher = more weight on recent runs. |
330340
| `--settings` | `-s` | PATH | Path to `settings.ini` |
341+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
331342

332343
---
333344

@@ -374,6 +385,7 @@ rushti build --tm1-instance INSTANCE [options]
374385
| `--tm1-instance` | | STR | TM1 instance name from `config.ini` (*required*) |
375386
| `--force` | `-f` | FLAG | Delete and recreate existing objects |
376387
| `--settings` | `-s` | PATH | Path to `settings.ini` |
388+
| `--config` | | PATH | Path to `config.ini` (TM1 connection parameters). Overrides `RUSHTI_DIR`/default location. |
377389
| `--log-level` | `-L` | CHOICE | Override log level |
378390

379391
### Examples

docs/advanced/settings-reference.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ RushTI searches for `settings.ini` in the following order:
3333

3434
If no file is found, built-in defaults are used for all settings.
3535

36+
### config.ini location
37+
38+
`config.ini` (TM1 connection parameters) is resolved separately, with its own
39+
precedence (highest wins):
40+
41+
1. `--config` CLI flag (TM1-connecting commands: `run`, `build`, `tasks …`, `resume`)
42+
2. `RUSHTI_DIR` environment variable (looks for `config/config.ini` under this directory)
43+
3. `./config.ini` (current directory -- legacy location, deprecation warning emitted)
44+
4. `./config/config.ini` (recommended location)
45+
46+
`--config` relocates **only** `config.ini`; `settings.ini` keeps `--settings`
47+
and `logging_config.ini` keeps its own resolution. Use it to share a single
48+
read-only `config.ini` with other tm1py utilities. A missing `--config` path
49+
fails fast (exit 1, no traceback). When `--config` is absent, resolution is
50+
unchanged.
51+
3652
---
3753

3854
## Configuration Sections

src/rushti/app_paths.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
can be emitted once logging is initialized.
77
"""
88

9+
import argparse
910
import logging
1011
import os
1112

@@ -15,6 +16,7 @@
1516
"CURRENT_DIRECTORY",
1617
"resolve_config_path",
1718
"log_legacy_path_warnings",
19+
"add_config_arg",
1820
]
1921

2022

@@ -73,6 +75,26 @@ def resolve_config_path(filename: str, warn_on_legacy: bool = True, cli_path: st
7375
return new_path
7476

7577

78+
def add_config_arg(parser: argparse.ArgumentParser) -> None:
79+
"""Add the ``--config`` argument to a parser.
80+
81+
Long-form only (``-c`` is taken by ``resume --checkpoint``). Relocates
82+
only ``config.ini`` (TM1 connection parameters); ``settings.ini`` and
83+
``logging_config.ini`` keep their own resolution. The resolved value is
84+
fed to :func:`resolve_config_path` as ``cli_path``.
85+
"""
86+
parser.add_argument(
87+
"--config",
88+
dest="config",
89+
default=None,
90+
metavar="FILE",
91+
help=(
92+
"Path to a config.ini file (TM1 connection parameters). "
93+
"Overrides RUSHTI_DIR/default location."
94+
),
95+
)
96+
97+
7698
def log_legacy_path_warnings(logger: logging.Logger) -> None:
7799
"""Log deprecation warnings for any legacy paths that were used.
78100

src/rushti/cli.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from TM1py.Utils import integerize_version
2020

2121
from rushti.app_paths import (
22+
add_config_arg,
2223
log_legacy_path_warnings,
2324
resolve_config_path,
2425
)
@@ -273,6 +274,9 @@ def create_argument_parser() -> argparse.ArgumentParser:
273274
# Add taskfile source arguments
274275
add_taskfile_source_args(parser, required=False, include_settings=True)
275276

277+
# Add --config (relocates config.ini only)
278+
add_config_arg(parser)
279+
276280
parser.add_argument(
277281
"--max-workers",
278282
"-w",
@@ -426,6 +430,7 @@ def parse_named_arguments(argv: list):
426430
"workflow": workflow,
427431
"log_level": args.log_level,
428432
"detailed_results": args.detailed_results,
433+
"config": args.config,
429434
}
430435

431436
return tasks_file_path, cli_args
@@ -471,6 +476,7 @@ def parse_arguments(argv: list):
471476
"exclusive": None,
472477
"no_checkpoint": False,
473478
"log_level": None, # Not supported in positional style
479+
"config": None, # Legacy positional style does not support --config
474480
}
475481
return tasks_file, cli_args
476482

@@ -626,6 +632,14 @@ def main() -> int:
626632
if resume_context:
627633
cli_args.update(resume_context)
628634

635+
# Resolve config.ini location, threading the resolved path explicitly into
636+
# the TM1 connection layer (CLI --config > RUSHTI_DIR > legacy CWD > config/).
637+
# Fail fast with a clean message (no traceback) on an explicit bad path.
638+
try:
639+
config_path = resolve_config_path("config.ini", cli_path=cli_args.get("config"))
640+
except FileNotFoundError:
641+
sys.exit(f"RushTI: --config file not found: {cli_args.get('config')}")
642+
629643
# Apply log level override if specified
630644
apply_log_level(cli_args.get("log_level"))
631645

@@ -645,7 +659,7 @@ def main() -> int:
645659
try:
646660
from rushti.tm1_integration import read_taskfile_from_tm1, connect_to_tm1_instance
647661

648-
tm1_source = connect_to_tm1_instance(tm1_instance, CONFIG)
662+
tm1_source = connect_to_tm1_instance(tm1_instance, config_path)
649663
try:
650664
# Resolve execution mode for TM1 read (affects predecessor parsing)
651665
tm1_mode = "opt" if cli_args.get("execution_mode") == ExecutionMode.OPT else "norm"
@@ -752,6 +766,7 @@ def main() -> int:
752766
tasks_file_path=tasks_file_path_for_services if not tm1_taskfile else None,
753767
workflow=workflow,
754768
exclusive=exclusive_mode,
769+
config_path=config_path,
755770
tm1_instances=tm1_instances_needed,
756771
)
757772

@@ -1106,7 +1121,7 @@ def main() -> int:
11061121
)
11071122
tm1_upload = connect_to_tm1_instance(
11081123
upload_instance,
1109-
CONFIG,
1124+
config_path,
11101125
)
11111126
try:
11121127
results_df = build_results_dataframe(

0 commit comments

Comments
 (0)