ligoj-cli 1.2.0__tar.gz → 1.3.0__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.
Files changed (59) hide show
  1. {ligoj_cli-1.2.0/ligoj_cli.egg-info → ligoj_cli-1.3.0}/PKG-INFO +199 -25
  2. ligoj_cli-1.2.0/PKG-INFO → ligoj_cli-1.3.0/README.md +195 -54
  3. ligoj_cli-1.2.0/README.md → ligoj_cli-1.3.0/ligoj_cli.egg-info/PKG-INFO +228 -23
  4. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligoj_cli.egg-info/SOURCES.txt +9 -0
  5. ligoj_cli-1.3.0/ligojcli/data/ldap/custom-schema.ldif +9 -0
  6. ligoj_cli-1.3.0/ligojcli/data/ldap/dev.ldif +71 -0
  7. ligoj_cli-1.3.0/ligojcli/data/nodes/artifactory.local.json +14 -0
  8. ligoj_cli-1.3.0/ligojcli/data/nodes/jenkins.json +14 -0
  9. ligoj_cli-1.3.0/ligojcli/data/nodes/ldap.json +90 -0
  10. ligoj_cli-1.3.0/ligojcli/data/nodes/ldap.local.json +90 -0
  11. ligoj_cli-1.3.0/ligojcli/data/nodes/nexus.local.json +14 -0
  12. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_debug.py +152 -13
  13. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/__init__.py +1 -1
  14. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/_common.py +8 -6
  15. ligoj_cli-1.3.0/ligojcli/dev_demo/_names.py +512 -0
  16. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/_seed.py +64 -28
  17. ligoj_cli-1.3.0/ligojcli/dev_demo/plugin_id_ldap.py +496 -0
  18. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_registry_artifactory.py +1 -1
  19. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_registry_nexus.py +1 -1
  20. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_plugin.py +778 -52
  21. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_test.py +32 -2
  22. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/ligoj.py +5 -0
  23. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/dev.py +345 -30
  24. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/ligoj.py +2 -1
  25. ligoj_cli-1.3.0/ligojcli/plugins/update.py +73 -0
  26. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/utils.py +5 -0
  27. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/pyproject.toml +16 -3
  28. ligoj_cli-1.2.0/ligojcli/dev_demo/plugin_id_ldap.py +0 -147
  29. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/LICENSE +0 -0
  30. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligoj_cli.egg-info/dependency_links.txt +0 -0
  31. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligoj_cli.egg-info/entry_points.txt +0 -0
  32. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligoj_cli.egg-info/requires.txt +0 -0
  33. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligoj_cli.egg-info/top_level.txt +0 -0
  34. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/__init__.py +0 -0
  35. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/assets/logo.png +0 -0
  36. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_backup.py +0 -0
  37. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/_subscribe.py +0 -0
  38. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_build_jenkins.py +0 -0
  39. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_prov_aws.py +0 -0
  40. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_prov_azure.py +0 -0
  41. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_qa_sonarqube.py +0 -0
  42. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_registry_harbor.py +0 -0
  43. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_scm_github.py +0 -0
  44. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_demo/plugin_scm_gitlab.py +0 -0
  45. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/dev_package.py +0 -0
  46. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/__init__.py +0 -0
  47. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/alfresco.py +0 -0
  48. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/argocd.py +0 -0
  49. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/bootstrap.py +0 -0
  50. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/build.py +0 -0
  51. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/gitlab.py +0 -0
  52. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/harbor.py +0 -0
  53. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/id.py +0 -0
  54. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/jenkins.py +0 -0
  55. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/nexus.py +0 -0
  56. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/prov.py +0 -0
  57. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/sonarqube.py +0 -0
  58. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/ligojcli/plugins/ssl.py +0 -0
  59. {ligoj_cli-1.2.0 → ligoj_cli-1.3.0}/setup.cfg +0 -0
@@ -1,13 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ligoj-cli
3
- Version: 1.2.0
4
- Summary: Ligoj CLI
3
+ Version: 1.3.0
4
+ Summary: Command-line client for the Ligoj REST API, with a local dev-environment toolkit
5
5
  Author-email: Fabrice Daugan <fdaugan@kloudy.io>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/ligoj/cli
8
8
  Project-URL: Documentation, https://github.com/ligoj/cli/README.md
9
9
  Project-URL: Repository, https://github.com/ligoj/cli
10
10
  Project-URL: Issues, https://github.com/ligoj/cli/issues
11
+ Keywords: ligoj,cli,rest,api,devops,automation,finops,cloud,provisioning,podman
12
+ Classifier: Development Status :: 5 - Production/Stable
11
13
  Classifier: Programming Language :: Python :: 3
12
14
  Classifier: Programming Language :: Python :: 3.11
13
15
  Classifier: Programming Language :: Python :: 3.12
@@ -68,6 +70,19 @@ pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/
68
70
 
69
71
  For local development from a checkout, see [Development](#development).
70
72
 
73
+ ## Updating
74
+
75
+ The CLI updates itself through `uv`:
76
+
77
+ ```bash
78
+ ligoj update # upgrade to the latest release (uv tool upgrade)
79
+ ligoj update --target 1.3.0 # pin a specific version (uv tool install --force)
80
+ ```
81
+
82
+ When the CLI was installed with `pipx`/`pip` instead of `uv`, update it with the
83
+ matching command (`pipx upgrade ligoj-cli` / `pip install -U ligoj-cli`) —
84
+ `ligoj update` reminds you of these when `uv` is not available.
85
+
71
86
 
72
87
  # Configuration
73
88
 
@@ -1039,7 +1054,7 @@ Input `--from` JSON:
1039
1054
  - JSON can be as list or dict (compact). See sample.
1040
1055
  - The parameters marked as sensitive are encrypted in database of Ligoj.
1041
1056
 
1042
- Content of sample [ligoj-ldap.json](docs/nodes/ldap.json) file:
1057
+ Content of sample [ligoj-ldap.json](ligojcli/data/nodes/ldap.json) file:
1043
1058
 
1044
1059
  ```json
1045
1060
  [
@@ -1830,16 +1845,22 @@ Artifactory + kind at once) is heavy, so `dev init` also **enforces the podman m
1830
1845
  if it has fewer than **6 vCPU** or **23 GB RAM** it is **stopped, resized up to that minimum, and
1831
1846
  restarted** (a fresh machine is created already sized; a machine that already exceeds the minimum is
1832
1847
  left untouched). On macOS it also checks the tools `dev demo` needs
1833
- later — **Java 21** (installed as the Temurin JDK cask via Homebrew) and **Maven 3.9.6** (installed
1834
- via [SDKMAN](https://sdkman.io), bootstrapped if missing); these two are best-effort and never abort
1835
- `init`. Pass `--skip-prereqs` to skip all these checks. Each service streams live progress and is
1848
+ later — **Java 25** (installed as the Temurin JDK cask via Homebrew) and **Maven 3.9.16** (installed
1849
+ via [SDKMAN](https://sdkman.io), bootstrapped if missing) — and **Node.js 26** (any newer version is
1850
+ accepted; installed via [nvm](https://github.com/nvm-sh/nvm) when absent, and pointed at by
1851
+ `nvm alias default` so new terminals pick it up — the already-open shell keeps its version until
1852
+ `nvm use 26`). All three are best-effort and never abort `init`. It also runs **`npm install-scripts approve fsevents`** in the app-ui webapp: npm ≥ 11.19
1853
+ blocks dependency install scripts until approved per project, and an unapproved `fsevents` silently
1854
+ degrades Vite's file watching to slow polling (the approval lands in the webapp's `package.json`
1855
+ `allowScripts`; with only an older npm on the machine there is nothing to approve and the step just
1856
+ notes it). Pass `--skip-prereqs` to skip all these checks. Each service streams live progress and is
1836
1857
  **idempotent** — a running pod is reused; use `--recreate` to replace it.
1837
1858
 
1838
1859
  | Service | Pod / release | Default port | Image | What `dev init` configures |
1839
1860
  | ------------ | ------------- | ------------ | ------------------------------------- | -------------------------- |
1840
1861
  | `postgresql` | `ligoj-db` | `5432` | `postgres:17` | `ligoj/ligoj` user/db (what `ligoj-api` expects), persistent volume `ligoj_db_data` |
1841
- | `openldap` | `openldap` | `1389` | `bitnamilegacy/openldap:latest` | `Manager` / `dc=sample,dc=com`; generates the admin password if missing; volume `openldap_data` |
1842
- | `keycloak` | `keycloak` | `9083` | `quay.io/keycloak/keycloak:26.6.1` | **backed by the shared `postgresql`** (dedicated `keycloak` database); realm `ligoj`, LDAP user federation, confidential `ligoj` client; prints Spring Boot properties |
1862
+ | `openldap` | `openldap` | `1389` | `bitnamilegacy/openldap:latest` | `Manager` / `dc=sample,dc=com`; generates the admin password if missing; volume `openldap_data`; installs the **custom schema** (`uidFonctionnel` attribute + `mefiPersonne` auxiliary class, backing the demo node's `people-custom-attributes` / `people-class-create`) — written to the mounted schema dir for a first boot **and** loaded over `ldapi:///` into an already-initialized volume; then seeds the base DIT (OUs + sample users). Waits for bitnami's *final* slapd (its first-boot init runs a temporary one) |
1863
+ | `keycloak` | `keycloak` | `9083` | `quay.io/keycloak/keycloak:26.7.3` | **backed by the shared `postgresql`** (dedicated `keycloak` database); realm `ligoj`, LDAP user federation, confidential `ligoj` client; prints Spring Boot properties |
1843
1864
  | `jenkins` | `jenkins` | `8085` | `jenkins/jenkins:2.570-slim-jdk25` | volume `jenkins_home`; provisions the admin user and generates an API token |
1844
1865
  | `sonarqube` | `sonarqube` | `9000` | `sonarqube:26.6.0.123539-community` | **backed by the shared `postgresql`** (dedicated `sonarqube` database); changes the default admin password and creates an API token |
1845
1866
  | `gitlab` | `gitlab` | `8929` (+ssh `2289`) | `gitlab/gitlab-ce:latest` | omnibus CE (single container), trimmed footprint; root password in `[dev]` |
@@ -1863,7 +1884,7 @@ are **read** before a secret is generated, so you stay in control:
1863
1884
  | Service | Inputs (option · env · `[dev]` key) |
1864
1885
  | ------------ | -------------------------------------------------------------------------------------------------- |
1865
1886
  | `postgresql` | `DB_IMAGE`·`db_image`, `DB_PORT`·`db_port`, `POSTGRES_USER`·`db_user`, `POSTGRES_PASSWORD`·`db_password`, `POSTGRES_DB`·`db_name` |
1866
- | `openldap` | `LDAP_IMAGE`·`ldap_image`, `LDAP_PORT`·`ldap_port`, `LDAP_ADMIN_USERNAME`·`ldap_admin_user`, `LDAP_ROOT`·`ldap_root`, `LDAP_ADMIN_PASSWORD`·`ldap_admin_password`, `LDAP_SCHEMA_DIR`·`ldap_schema_dir` |
1887
+ | `openldap` | `LDAP_IMAGE`·`ldap_image`, `LDAP_PORT`·`ldap_port`, `LDAP_ADMIN_USERNAME`·`ldap_admin_user`, `LDAP_ROOT`·`ldap_root`, `LDAP_ADMIN_PASSWORD`·`ldap_admin_password`, `LDAP_SCHEMA_DIR`·`ldap_schema_dir`; demo people: `DEMO_LDAP_USERS`·`demo_ldap_users` (default `10000`, `0` disables), `DEMO_MAIL_DOMAIN`·`demo_mail_domain` (default: the LDAP root's `dc=` parts, e.g. `sample.com`) |
1867
1888
  | `keycloak` | `KEYCLOAK_IMAGE`·`keycloak_image`, `KEYCLOAK_PORT`·`keycloak_port`, `KC_BOOTSTRAP_ADMIN_USERNAME`·`keycloak_admin_user`, `KC_BOOTSTRAP_ADMIN_PASSWORD`·`keycloak_admin_password`, `KEYCLOAK_LDAP_URL`·`keycloak_ldap_url`, `KEYCLOAK_DB_PASSWORD`·`keycloak_db_password` (shared-DB role) |
1868
1889
  | `jenkins` | `JENKINS_IMAGE`·`jenkins_image`, `JENKINS_PORT`·`jenkins_port`, `JENKINS_API_USER`·`jenkins_api_user`, `JENKINS_ADMIN_PASSWORD`·`jenkins_admin_password`, `JENKINS_API_TOKEN`·`jenkins_api_token` |
1869
1890
  | `sonarqube` | `SONAR_IMAGE`·`sonar_image`, `SONAR_PORT`·`sonar_port`, `SONAR_ADMIN_PASSWORD`·`sonar_admin_password`, `SONAR_DB_PASSWORD`·`sonar_db_password` (shared-DB role) |
@@ -2061,6 +2082,14 @@ ligoj dev demo --list # just list installed plugins (id, name, version) and
2061
2082
  ligoj dev demo --only plugin-id-ldap plugin-build-jenkins
2062
2083
  ```
2063
2084
 
2085
+ **Idempotent by design.** Every demo step checks before it creates: projects (`project_get` first),
2086
+ subscriptions (an existing subscription of the node on the project with the same parameters is
2087
+ reused, never duplicated), nodes (upsert), tool resources (Jenkins job, GitLab/Harbor project,
2088
+ Nexus/Artifactory repository, Sonar user/project — "already exists" is treated as success), and
2089
+ the LDAP people/groups (fixed seeds + `ldapadd -c`). Running `dev demo` twice in a row leaves the
2090
+ same data in place.
2091
+
2092
+
2064
2093
  It (1) checks Ligoj is up via `/manage/health`, (2) lists the installed plugins with
2065
2094
  [`plugin list`](#plugin), (3) runs the demo registered for each one, then (4) creates the demo
2066
2095
  projects and their [link subscriptions](#demo-projects-and-link-subscriptions). Connection values
@@ -2071,12 +2100,12 @@ Each plugin's demo lives in its own module under `ligojcli/dev_demo/`:
2071
2100
 
2072
2101
  | Plugin artifact | What the demo does |
2073
2102
  | ----------------------------- | --------------------------------------------------------------------------------------- |
2074
- | `plugin-id-ldap` | Upserts the `service:id:ldap:local` node (from [docs/nodes/ldap.local.json](docs/nodes/ldap.local.json), with the live URL / bind DN / password), makes it the primary IAM, restarts the context, then creates the reference OUs, company/group container scopes and technical groups |
2103
+ | `plugin-id-ldap` | Upserts the `service:id:ldap:local` node (from [ligojcli/data/nodes/ldap.local.json](ligojcli/data/nodes/ldap.local.json), with the live URL / bind DN / password), makes it the primary IAM (and sets the identity display options `service:id:visual-id-name=customAttributes.uidFonctionnel`, `service:id:visual-id-label=Matricule`, `service:id:user-display=${firstName} ${lastName}`), sets the people display configurations — `service:id:user-display` = `${firstName} ${lastName}`, `service:id:visual-id-name` = `customAttributes.<first custom attribute>` (`uidFonctionnel`, shown as the user's identifier instead of the uid) and `service:id:visual-id-label` = `Matricule` — restarts the context, creates the reference OUs, company/group container scopes and technical groups, then **seeds 10 000 demo people** straight into LDAP (`ldapadd` inside the pod, ~35 s; a re-run is idempotent): unique random first/last names from an international pool (accented names are base64-encoded in the LDIF), mail `first.last@<domain>`, a unique **9-character uppercase alphanumeric `uid`**, password `ligoj-user`, spread over `ou=department1…5` under `people-internal-dn` (created when missing, discovered as companies). When the node declares **`people-custom-attributes`**, every user also gets each such attribute set to its mail, with the **`people-class-create`** objectClass that allows it (`uidFonctionnel` / `mefiPersonne` by default). Then **100 demo groups** (`<domain>-<team>`, e.g. `billing-core`, under the Project scope `ou=project,ou=groups`) with **50 % of the people in no group, 40 % in one, 10 % in two** (never an empty group). Both the people and the memberships come from **fixed seeds**, so a re-run regenerates the *same* entries and `ldapadd -c` reports them as already present — never 10K new users. The `id-ldap-data` cache is invalidated afterwards so they show up immediately. Count/domain: `demo_ldap_users`, `demo_mail_domain` |
2075
2104
  | `plugin-build-jenkins` | Upserts the `service:build:jenkins:local` node (url / user / api-token) |
2076
2105
  | `plugin-scm-gitlab` | Upserts the `service:scm:gitlab:local` node (url / user / auth-key) |
2077
2106
  | `plugin-registry-harbor` | Upserts the `service:registry:harbor:local` node (url / user / password) |
2078
- | `plugin-registry-nexus` | Upserts the `service:registry:nexus:local` node (from [docs/nodes/nexus.local.json](docs/nodes/nexus.local.json), with the live url / user / password) |
2079
- | `plugin-registry-artifactory` | Upserts the `service:registry:artifactory:local` node (from [docs/nodes/artifactory.local.json](docs/nodes/artifactory.local.json), with the live url / user / password) |
2107
+ | `plugin-registry-nexus` | Upserts the `service:registry:nexus:local` node (from [ligojcli/data/nodes/nexus.local.json](ligojcli/data/nodes/nexus.local.json), with the live url / user / password) |
2108
+ | `plugin-registry-artifactory` | Upserts the `service:registry:artifactory:local` node (from [ligojcli/data/nodes/artifactory.local.json](ligojcli/data/nodes/artifactory.local.json), with the live url / user / password) |
2080
2109
  | `plugin-prov-aws` | Upserts the `service:prov:aws:local` node from the `[dev]` AWS credentials — `aws_access_key_id`, `aws_secret_access_key`, `aws_account_id` (all required) |
2081
2110
  | `plugin-prov-azure` | Upserts the `service:prov:azure:local` node from the `[dev]` Azure service principal — `azure_tenant_id`, `azure_subscription_id`, `azure_application_id`, `azure_client_secret` (required) and `azure_resource_group` (optional) |
2082
2111
 
@@ -2146,7 +2175,11 @@ linking.
2146
2175
 
2147
2176
  Finally, `dev demo` fills the tools with real data so the demo project has something to show. This
2148
2177
  step is **heavy** (image pulls, two Maven builds, a Sonar analysis and two git mirrors — several
2149
- minutes) and runs on a full `dev demo` (it is skipped when you pass `--only`). The tools are seeded
2178
+ minutes) and runs on a full `dev demo` (it is skipped when you pass `--only`). **Only the tools
2179
+ of the plugins actually installed in Ligoj are seeded** — a tool whose plugin is absent (say GitLab
2180
+ without `plugin-scm-gitlab`) is never contacted, and the run prints which seeders it skipped and
2181
+ why. The Maven step narrows the same way: it deploys to Nexus and/or Artifactory and runs the Sonar
2182
+ analysis only for the ones whose plugin is installed. The tools are seeded
2150
2183
  in parallel, best-effort — a failing tool logs a warning and never aborts the rest:
2151
2184
 
2152
2185
  | Tool | Data seeded |
@@ -2194,6 +2227,8 @@ stack you actually debug: IntelliJ IDEA plus the two Ligoj Spring Boot apps and
2194
2227
 
2195
2228
  | Component | Started by `dev debug` | Endpoint / path |
2196
2229
  | --------------- | ------------------------------------------------------- | --------------- |
2230
+ | PostgreSQL | the `ligoj-db` pod (`podman pod start`, machine too) | `localhost:5432` |
2231
+ | OpenLDAP | the `openldap` pod (`podman pod start`) | `localhost:1389` |
2197
2232
  | IntelliJ IDEA | `open -a "IntelliJ IDEA" <project>` (if stopped) | `~/git/ligoj` |
2198
2233
  | `ligoj-api` | the **dedicated launcher app**, in Debug mode | `http://localhost:8081/ligoj-api` |
2199
2234
  | `ligoj-ui` | the **dedicated launcher app**, in Debug mode | `http://localhost:8080/ligoj` |
@@ -2201,19 +2236,56 @@ stack you actually debug: IntelliJ IDEA plus the two Ligoj Spring Boot apps and
2201
2236
 
2202
2237
  ```bash
2203
2238
  ligoj dev debug init # compile the dedicated launcher app (one-time; re-run after renaming a config)
2204
- ligoj dev debug start # open IntelliJ + Debug-launch the API/UI + start Vite (only those stopped)
2239
+ ligoj dev debug start # start the ligoj-db + openldap pods + IntelliJ + API/UI/Vite, then open the app in the browser
2240
+ ligoj dev debug start --no-browser # same without opening the browser
2205
2241
  ligoj dev debug status # show what is running (process) and reachable (port), no changes
2206
- ligoj dev debug stop # stop the API/UI/Vite apps (IntelliJ stays open to protect unsaved work)
2207
- ligoj dev debug restart # stop then start the apps
2242
+ ligoj dev debug stop # stop the API/UI/Vite apps AND the two pods (IntelliJ stays open)
2243
+ ligoj dev debug restart # stop then start the apps (the pods are left running)
2208
2244
  ligoj dev debug start -w 60 # same live '--wait' as the other dev commands (0 = no wait)
2245
+ ligoj dev debug start vite # start ONLY the Vite dev server (nothing else is touched)
2246
+ ligoj dev debug stop vite # stop ONLY Vite; 'restart vite' bounces it (pods, IDE, Java apps untouched)
2209
2247
  ```
2210
2248
 
2249
+ `start vite` needs the webapp dependencies installed (`npm install` in `app-ui/src/main/webapp`):
2250
+ without them the command says so at once instead of waiting for a port that never opens, and a
2251
+ Vite process that exits right after launch is reported with the tail of its log
2252
+ (`~/.ligoj/dev/debug/vite.log`). Only Vite can be driven alone: the Java apps are started together
2253
+ by the launcher app, which starts every run configuration that is not running.
2254
+
2255
+ **Browser.** Once the wait completes, `start` opens the application in your browser — the **Vite**
2256
+ dev server (`http://localhost:5173/ligoj/`, live reload) when it answers, else the UI server
2257
+ (`http://localhost:8080/ligoj`); nothing is opened when neither is up yet or with `--no-browser`
2258
+ / `--wait 0`.
2259
+
2260
+ **Backing services first.** `start` brings the **dev PostgreSQL** (`ligoj-db` pod) and **OpenLDAP**
2261
+ (`openldap` pod) up before anything else — `ligoj-api` cannot boot without the DB, and the LDAP
2262
+ identity backend should be there too — starting the podman machine when it is down. A service already
2263
+ answering on its port is a no-op; a pod that was **never created** only warns (run
2264
+ `ligoj dev init --only <service>`) so the IDE stack still launches. Symmetrically, **`dev debug stop`
2265
+ also stops both pods** (skipped quietly when podman itself is down); `restart` only bounces the apps
2266
+ and leaves the pods running.
2267
+
2211
2268
  **Why `init` / the launcher app.** IntelliJ has no headless "run this configuration" command, and
2212
2269
  scripting its UI needs the broad macOS **Accessibility** permission (control any app + read the
2213
2270
  screen). Instead of granting that to your whole terminal, `dev debug init` compiles a tiny dedicated
2214
2271
  app (default `~/Applications/Ligoj Debug.app`) that drives IntelliJ's *Run ▶ Debug…* chooser for
2215
2272
  `ligoj-api` / `ligoj-ui` (skipping any already running). You grant Accessibility to **that app only**
2216
2273
  — the first `dev debug start` triggers the macOS prompt — and can then revoke your terminal's grant.
2274
+
2275
+ **Granting (and re-granting) Accessibility.** The grant is keyed on the app's signature, so every
2276
+ re-`init` (and some macOS updates) invalidates it — and a broken grant fails *silently*: `Ligoj
2277
+ Debug` launches and stays open, IntelliJ comes to the front, but the run configurations never start
2278
+ (`dev debug start` now names this cause when it happens). The reliable order, also printed by
2279
+ `dev debug init`:
2280
+
2281
+ 1. In **System Settings ▸ Privacy & Security ▸ Accessibility**, **remove** any existing
2282
+ `Ligoj Debug` / `applet` row (`−`) — toggling a **stale** row does nothing;
2283
+ 2. launch the app once (`open ~/Applications/Ligoj\ Debug.app` or `dev debug start`) and approve the
2284
+ *"control this computer"* prompt — beware, it can sit **hidden behind windows or on another
2285
+ display/Space**, unanswered, looking like nothing happened;
2286
+ 3. the row reappears ticked. To force a clean re-prompt: `tccutil reset Accessibility
2287
+ org.ligoj.dev.debug`, then redo 1–2.
2288
+
2217
2289
  When `dev debug start` launches a **cold** IntelliJ, the launcher first **waits (up to 180 s) for the
2218
2290
  IDE to become UI-ready** — its *Run* menu populated, i.e. the project frame is up — before sending any
2219
2291
  keystroke, so a not-yet-started IDE no longer drops the Debug commands. Because that logic is baked
@@ -2275,19 +2347,32 @@ build` runs that build for every **live** plugin — the ones installed in the r
2275
2347
  # Rebuild the frontend of every live plugin (in parallel)
2276
2348
  ligoj dev plugin build
2277
2349
 
2278
- # Build only specific plugins (skips the live lookup, so Ligoj need not be running)
2350
+ # Build EVERY locally checked-out plugin that has a ui/ (no Ligoj instance needed)
2351
+ ligoj dev plugin build --all
2352
+
2353
+ # Build only specific plugins (also skips the live lookup)
2279
2354
  ligoj dev plugin build --only plugin-ui plugin-id
2280
2355
 
2281
2356
  # Limit parallelism
2282
2357
  ligoj dev plugin build --jobs 2
2283
2358
  ```
2284
2359
 
2360
+ Two flags select what to build, and both work **offline**, straight from the working copies — like
2361
+ `dev plugin renovate --all`, they never query the Ligoj API:
2362
+
2363
+ - **`--all` / `-A`** — every directory under the plugins dir that has a `ui/package.json`. Because it
2364
+ reads the checkouts rather than the running instance, it also covers plugins that are not (or not
2365
+ yet) installed in Ligoj.
2366
+ - **`--only` / `-O`** — an explicit artifact list.
2367
+
2368
+ They are mutually exclusive. With **neither**, the set comes from the running Ligoj (`system/plugin`),
2369
+ so the instance must be reachable — the error names both escapes if it isn't.
2370
+
2285
2371
  Dependencies are installed automatically on first build (`npm ci` when a `package-lock.json` is
2286
2372
  present, otherwise `npm install`) before `npm run build`. Builds run in parallel (default
2287
2373
  `min(4, CPUs)`, `--jobs` to change) and each plugin is reported `OK` / `FAILED` independently — one
2288
2374
  failing frontend never aborts the others. The plugins directory is `LIGOJ_PLUGINS_DIR` /
2289
- `[dev] ligoj_plugins_dir` (default `~/git/ligoj-plugins`), and `npm` must be on the `PATH`. Without
2290
- `--only`, Ligoj must be reachable so the live plugin set can be listed.
2375
+ `[dev] ligoj_plugins_dir` (default `~/git/ligoj-plugins`), and `npm` must be on the `PATH`.
2291
2376
 
2292
2377
  ## Renovate a plugin's dependencies (`dev plugin renovate`)
2293
2378
 
@@ -2299,9 +2384,15 @@ in the working tree for you to review:
2299
2384
  latest local `org.ligoj.api:parent` release; override with `--parent-version`). A current version
2300
2385
  newer than the target is left alone; the project's own `<version>` is never touched.
2301
2386
  - **`package.json`** — re-pins only the npm dependency constraints that are **also** declared by the
2302
- host UI to the host's versions (none added/removed; `scripts` and non-shared deps untouched).
2303
- - **`package-lock.json`** — regenerated from `package.json` (`npm install --package-lock-only`) so the
2304
- plugin's `npm ci` stays in sync.
2387
+ host UI to the host's versions (none added/removed; `scripts` and non-shared deps untouched), and
2388
+ **merges the host's `allowScripts` entries in** (the npm ≥ 11.19 install-script approvals, e.g.
2389
+ `fsevents` — plugin-specific approvals are kept, host entries win on conflict).
2390
+ - **`package-lock.json`** — regenerated **and advanced** via `npm update --package-lock-only`: every
2391
+ dependency (direct and transitive) moves to the newest version its semver range allows, while the
2392
+ lockfile stays in sync with `package.json` for `npm ci` (constraints themselves are not touched).
2393
+ `updated` is reported only when something **effectively** moved
2394
+ (`package.json` text or lockfile bytes) — re-running moments later shows every plugin as
2395
+ up-to-date and ends with `N analyzed, 0 updated, N up-to-date, 0 error(s)`.
2305
2396
 
2306
2397
  ```bash
2307
2398
  # Renovate the plugin in the current directory
@@ -2310,16 +2401,97 @@ ligoj dev plugin renovate
2310
2401
  # A specific plugin (artifact under LIGOJ_PLUGINS_DIR, or a path)
2311
2402
  ligoj dev plugin renovate plugin-km
2312
2403
 
2313
- # Every plugin under LIGOJ_PLUGINS_DIR
2404
+ # Every plugin under LIGOJ_PLUGINS_DIR, 3 at a time (live one-line-per-plugin report)
2314
2405
  ligoj dev plugin renovate --all
2406
+
2407
+ # More parallelism
2408
+ ligoj dev plugin renovate --all --jobs 6
2315
2409
  ```
2316
2410
 
2411
+ With more than one plugin the work runs in **parallel** (`--jobs` workers, default **3**) and every
2412
+ plugin gets **exactly one output line**. While in flight a plugin shows in a small live footer (at
2413
+ most `--jobs` rows, `… renovating (n/total done)`, rewritten in place); on completion that row is
2414
+ replaced by the plugin's permanent result line — colored, with emoji on a color terminal (`⏳`/`✅`/`💤`/`❌`; plain `…`/`✓`/`↷`/`✗` with `--no-color`) — `✓` changed with a short summary
2415
+ (`parent 4.3.0→4.3.2 · 2 dep(s) · allowScripts+2 · lockfile`), `↷` up-to-date, or `✗` error (failing
2416
+ plugins get their npm output printed after the run, and their `package.json` edit is reverted).
2417
+ Keeping the live region no taller than the worker count is what makes the rendering reliable on any
2418
+ terminal height — a full one-row-per-plugin block would scroll and duplicate. Piped output prints one
2419
+ final line per plugin instead. A **single** plugin keeps the verbose report with each dependency
2420
+ re-pin on its own line.
2421
+
2317
2422
  The host UI referential is `LIGOJ_HOST_PACKAGE_JSON` (default
2318
2423
  `~/git/ligoj/app-ui/src/main/webapp/package.json`, override with `--host-package-json`), the plugins
2319
2424
  root is `LIGOJ_PLUGINS_DIR` / `--plugins-dir` (default `~/git/ligoj-plugins`), and `npm` must be on the
2320
2425
  `PATH`. A plugin must be an `org.ligoj.api:plugin-parent` project — anything else is skipped (with
2321
2426
  `--all`) or reported as an error (when named).
2322
2427
 
2428
+ ## Deploy a plugin to a Ligoj instance (`dev plugin deploy`)
2429
+
2430
+ `dev plugin deploy <plugin> [<plugin> ...]` builds one or more plugins and installs them on a
2431
+ running Ligoj — the fast inner loop for plugin development against a real instance:
2432
+
2433
+ 1. **build** — `mvn clean package` (tests skipped) in each plugin checkout, **all builds before any
2434
+ upload**, so a failed build aborts the deploy before the instance receives anything. The jar is
2435
+ **code-signed** when `~/.ligoj/code-signing.p12` exists and its password is available
2436
+ (`LIGOJ_SIGN_STOREPASS`, else the macOS keychain entry `ligoj.release.sign-storepass`); otherwise
2437
+ it is built unsigned, with a warning (`--skip-build` reuses the jars already in `target/`);
2438
+ 2. **upload** — every jar, exactly what `ligoj plugin upload --from <jar> --force` does, so a
2439
+ same-version (`-SNAPSHOT`) redeploy replaces the installed jar;
2440
+ 3. **restart + wait** — the Ligoj context is restarted **once for the whole set** and the command
2441
+ waits until the restart has actually **completed**: the API is observed going *down* and then
2442
+ *up* again (a restart is asynchronous — an immediate "UP" would be the old context), and every
2443
+ plugin is confirmed in the installed list with its version. `--wait N` bounds the wait;
2444
+ `--wait 0` returns right after the restart request.
2445
+
2446
+ The three steps are announced as they start. The builds run in parallel (`--jobs`, default 3) with
2447
+ **one live line per plugin** (same rendering as `dev plugin renovate`: ⏳ building, then ✅ built
2448
+ with its duration and jar size, or ❌ the Maven error — whose log tail is printed after the
2449
+ report). The uploads are numbered. A **summary** then lists every plugin with its installed
2450
+ version, followed by the totals: build, upload and restart durations, installed count and errors.
2451
+ A plugin missing from the installed list after the restart makes the command fail.
2452
+
2453
+ Before building, the target is probed with an authenticated `GET session` (available to every
2454
+ user), falling over to `GET system/plugin` — the call the deploy relies on anyway — when the session
2455
+ view answers an error. Neither is the `/manage/health` actuator, which a hosted front such as a SaaS
2456
+ behind a CDN does not expose. The command stops with a one-line error, and no build, when the
2457
+ instance is unreachable, answers an error to both probes, **or rejects the profile's credentials**
2458
+ (401/403) — the latter names the `api_user`/`api_key` entries to check.
2459
+
2460
+ The **target instance comes from the active profile** — endpoint and credentials — which is the `dev`
2461
+ profile by default (like every `dev` command) and any other via the global option:
2462
+
2463
+ ```bash
2464
+ ligoj dev plugin deploy plugin-km # build + deploy to the dev profile's Ligoj
2465
+ ligoj dev plugin deploy plugin-km plugin-km-confluence # several plugins, ONE restart for all of them
2466
+ ligoj --profile staging dev plugin deploy plugin-km # ... to the 'staging' profile's instance
2467
+ ligoj dev plugin deploy ~/git/my-plugin --skip-build # a path, reusing the existing target/ jar
2468
+ ```
2469
+
2470
+ `<plugin>` is an artifact under `LIGOJ_PLUGINS_DIR` (`~/git/ligoj-plugins`, `--plugins-dir` to change)
2471
+ or a path to the checkout.
2472
+
2473
+ ## Pull the plugin checkouts (`dev plugin pull`)
2474
+
2475
+ `dev plugin pull` runs `git pull --ff-only` in every plugin checkout under the plugins dir (every
2476
+ sub-directory holding a `.git`), or only in the plugins named on the command line, three at a time
2477
+ by default:
2478
+
2479
+ ```bash
2480
+ ligoj dev plugin pull # every git checkout under ~/git/ligoj-plugins
2481
+ ligoj dev plugin pull plugin-km plugin-bt # only these (artifact names, or paths)
2482
+ ligoj dev plugin pull --jobs 6 # more parallel pulls
2483
+ ```
2484
+
2485
+ Each plugin gets **one report line**, live while it runs (same rendering as `dev plugin renovate`):
2486
+ ✅ *updated* with the branch and the number of new commits, 💤 *up-to-date* or *skipped*, or ❌ the
2487
+ git error. Pulls are **fast-forward only**: local commits are never merged over or rewritten — a
2488
+ diverged branch is reported as an error and left untouched for you to resolve, while a detached
2489
+ HEAD or a branch without upstream is skipped (nothing to pull, not an error). Submodule checkouts
2490
+ (a `.git` *file*) are pulled like plain clones. Credential prompts are disabled, so a repository
2491
+ needing an interactive login fails instead of hanging. The exit status is non-zero when any pull
2492
+ failed. The plugins dir comes from `--plugins-dir`, else `LIGOJ_PLUGINS_DIR` / the profile's
2493
+ `ligoj_plugins_dir`, else `~/git/ligoj-plugins`.
2494
+
2323
2495
  ## Build the app container images (`dev package`)
2324
2496
 
2325
2497
  `dev package` builds the two Ligoj application container images **locally**, straight from the
@@ -2361,12 +2533,13 @@ the release helper (`commands/release.sh`).
2361
2533
  While `dev debug` runs the apps from your IDE, `dev test` runs the **released Docker images**
2362
2534
  (`ligoj/ligoj-api` + `ligoj/ligoj-ui`) against the local dev stack — the quickest way to smoke-test a
2363
2535
  published build. It starts both containers in the background, waits until **both are healthy**, then
2364
- opens the UI in your browser at `http://localhost:<ui-port>/ligoj/`:
2536
+ opens the UI in your browser at `http://localhost:<ui-port><context>/` (default context `/ligoj`):
2365
2537
 
2366
2538
  ```bash
2367
2539
  ligoj dev test start # run both, wait for health, open the browser
2368
2540
  ligoj dev test stop # stop and remove both containers
2369
2541
  ligoj dev test start --tag 4.0.2-SNAPSHOT-101 --port 8089 --api-port 8088
2542
+ ligoj dev test start --context /ligoj2 # serve the UI under /ligoj2 (CONTEXT_URL; '/' = root)
2370
2543
  ligoj dev test start --no-browser --no-wait # start detached, don't wait or open the browser
2371
2544
  ligoj dev test -h # full option + '-D' reference (mirrors ligoj/DOC.md)
2372
2545
 
@@ -2390,7 +2563,7 @@ add the driver to your build. Pass an explicit `--api …` group to take full co
2390
2563
  **Networking** adapts to the runtime: **docker/Linux** uses `--network=host` (the API reaches the dev DB
2391
2564
  on `localhost`); **podman-machine** publishes ports (`-p <port>:<port>`) so the mac can reach
2392
2565
  `localhost:<port>`, and the containers reach the machine host — the other container and the dev DB — via
2393
- `host.containers.internal`. Override with `--net host|publish`.
2566
+ `host.containers.internal`; in publish mode both apps are also told to bind on all interfaces (`SERVER_HOST=0.0.0.0` — the images default to loopback, unreachable through a port mapping). Override with `--net host|publish`.
2394
2567
 
2395
2568
  Every option resolves from the CLI flag, then the environment, then `~/.ligoj/config` / `~/.ligoj/credentials`:
2396
2569
 
@@ -2398,6 +2571,7 @@ Every option resolves from the CLI flag, then the environment, then `~/.ligoj/co
2398
2571
  | ------ | ------- | ----------------- |
2399
2572
  | `--port` (UI port, also the browser port) | `8089` | `LIGOJ_UI_PORT` / `ligoj_ui_port` |
2400
2573
  | `--api-port` (UI `ENDPOINT` + API exposed port) | `8088` | `LIGOJ_API_PORT` / `ligoj_api_port` |
2574
+ | `--context` (UI context path, the image's `CONTEXT_URL`) | `/ligoj` | `LIGOJ_UI_CONTEXT` / `ligoj_ui_context` |
2401
2575
  | `--home` (`LIGOJ_HOME`) | `~/.ligoj` | `LIGOJ_HOME` / `ligoj_home` |
2402
2576
  | `--tag` / `--api-tag` / `--ui-tag` | newest **local** build, else latest published | `LIGOJ_TEST_TAG` / `ligoj_test_tag` |
2403
2577
  | `--runtime` | `docker` if present, else `podman` | `LIGOJ_TEST_RUNTIME` / `ligoj_test_runtime` |