4.0 KiB
Redmine CLI runtime
The live wrappers are deliberately short:
bin/rcontacts-live search acme
bin/rtickets-live search --where 'assigned_to IS NULL'
bin/rtl search --where 'assigned_to IS NULL' # short live alias
bin/rtd search --where 'assigned_to IS NULL' # explicit LAN/dev lane
--help works without credentials. The wrappers resolve configuration independently of the current working directory and pass ordinary arguments unchanged to redmine_contacts.py or redmine_tickets.py.
Diagnose configuration without API traffic
bin/rcontacts-live --doctor
bin/rtickets-live --show-config
bin/rtl --doctor-nmi
Diagnostics show effective paths and each setting’s source. Secrets are never printed. network_checked: false means readiness is local; it does not prove remote authentication.
Precedence and files
Highest priority wins:
- wrapper CLI options;
- exported environment;
- selected Redmine env file;
- ticket JSON/YAML
--configvalues; - defaults.
Select an env file with --env-file PATH or REDMINE_ENV_FILE. Otherwise the first existing file is used:
- live: checkout
.env, legacybin/.env,~/.redmine.live; - dev: checkout
.env.dev,bin/.env.dev,~/.redmine.dev.
Dev never falls back to the live file. An explicitly selected missing, empty, or malformed file is an error. Files use NAME=value and are parsed as data; shell commands are not evaluated.
REDMINE_API_KEY required for API operations
REDMINE_BASE_URL live default https://rm.ldrprep.com
REDMINE_PROJECT default customer-service
REDMINE_BASE_CACHE common mutable-data root
REDMINE_CONTACTS_CACHE exact full-CRM snapshot JSON file
REDMINE_TICKETS_CACHE exact ticket-cache directory
REDMINE_LOCK_TIMEOUT writer wait, seconds; default 60
REDMINE_ENV_FILE explicit env profile
REDMINE_API_KEY_FILE file containing only the Redmine key
NMI bridge variables (NMI_CLI, NMI_ENV_FILE, NMI_MODE, endpoint/credential variables) pass through to PHP. rtl defaults NMI to production; rtd defaults it to dev. --doctor-nmi runs the actual PHP resolver offline.
Cache layout
REDMINE_BASE_CACHE chooses the common root, defaulting to checkout cache/ live and cache-dev/ dev.
- Tickets normally use
<root>/redmine_tickets/. - Other endpoint/project combinations get deterministic distinct ticket directories.
- Fresh contacts setups use
<root>/redmine_contacts/<host>_<project>.json. - If historical
<root>/redmine_contactsis already a file for normal live use, the wrapper preserves and uses it. There is no automatic migration. - Tickets’
<ticket-cache>/contacts/mirror is a different per-contact format, not the full contacts snapshot.
Exact --cache-dir DIR (tickets) and --cache FILE (contacts) win. Contacts rejects a cache directory because redmine_contacts.py expects one JSON file.
ticket-contact prints a shell-quoted full-CRM handoff that retains endpoint, project, env profile, API-key-file context, and cache file without putting a key in argv.
Concurrency and cron
Writers use POSIX advisory locks around read/modify/write transactions and unique same-directory temporary files followed by atomic replacement. A process’s death releases its kernel lock; the persistent .lock file is only an inode anchor. A later holder removes matching temporary residue left by a killed writer.
Contention is visible on stderr. After REDMINE_LOCK_TIMEOUT, the process exits nonzero rather than making a cron failure silent.
REDMINE_ENV_FILE=/etc/ldr/redmine-live.env /opt/redmine/bin/rtickets-live sync --remote-updated-since 6h --run-log --quiet
Completion and safety
source bin/redmine-runtime-completion.bash
This registers all four wrappers and includes the established contacts completion surface.
The wrappers do not weaken write safety: production ticket writes still require --allow-prod-writes; customer email still requires its long confirmation; NMI retains its independent mutation gates.