@dennisrepa/elevate 1.7.0 → 1.8.0
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.
- package/README.md +8 -5
- package/dist/chunk-4YCMSRA6.js +5817 -0
- package/dist/chunk-4YCMSRA6.js.map +1 -0
- package/dist/cli.js +136 -3604
- package/dist/cli.js.map +1 -1
- package/dist/config-DRANL4H4.js +13 -0
- package/dist/config-DRANL4H4.js.map +1 -0
- package/docs/de.md +104 -24
- package/docs/en.md +104 -24
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/docs/de.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
## 🌟 Übersicht
|
|
9
9
|
|
|
10
|
-
**Elevate** ist ein interaktives Terminal-Dashboard (TUI) zur sicheren, selektiven und transparenten Aktualisierung von Abhängigkeiten in **Polyglot-Monorepos** (Node/npm & Java/
|
|
10
|
+
**Elevate** ist ein interaktives Terminal-Dashboard (TUI) zur sicheren, selektiven und transparenten Aktualisierung von Abhängigkeiten in **Polyglot-Monorepos** (Node/npm, Java/Maven, Rust/Cargo & Java/Gradle) sowie Einzelprojekten.
|
|
11
11
|
|
|
12
12
|
* **Feder-Symbolik (`🪶`) & Orange-Brand (`#FF8800`):** Leicht, modern und übersichtlich im Terminal.
|
|
13
|
-
* **Polyglot-Fähig:** Unterstützt gleichzeitig Frontend-Projekte (`package.json` mit npm Workspaces) und Backend-Projekte (`pom.xml` mit Maven).
|
|
13
|
+
* **Polyglot-Fähig:** Unterstützt gleichzeitig Frontend-Projekte (`package.json` mit npm Workspaces) und Backend-Projekte (`pom.xml` mit Maven, `build.gradle` mit Gradle, `Cargo.toml` mit Cargo).
|
|
14
14
|
* **Release Channels:** Filtert Vorabversionen (Beta, RC, Alpha, Milestone, Snapshot) standardmäßig heraus und schlägt ausschließlich produktionsreife Releases vor.
|
|
15
15
|
* **Animiertes Begleiter-Hühnchen („Pip“ 🐣):** Begleitet den Entwickler dezent im Terminal und reagiert auf Aktionen.
|
|
16
16
|
* **Bilinguales i18n:** Jederzeit umschaltbar zwischen Deutsch und Englisch via Taste **`[L]`**.
|
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
## ✨ Features & Highlights
|
|
21
21
|
|
|
22
|
-
1. **🌐 Polyglot Monorepo Support (npm, pnpm &
|
|
22
|
+
1. **🌐 Polyglot Monorepo Support (npm, pnpm, Maven, Cargo & Gradle):**
|
|
23
23
|
* **Node / npm:** Löst Workspaces genau wie npm auf (inklusive Glob-Mustern wie `packages/**`), berechnet SemVer-Diffs, aktualisiert `package.json`, führt `npm install` aus und prüft das Lockfile.
|
|
24
24
|
* **Node / pnpm** (9 – 12): Dasselbe für pnpm-Repositories — Workspaces aus `pnpm-workspace.yaml`, das `workspace:`-Protokoll, `catalog:`-Einträge, `pnpm install` und eine Lockfile-Prüfung. Repositories mit Yarn oder Bun werden abgelehnt.
|
|
25
25
|
* **Java / Maven:** Findet jede `pom.xml` (auch die Root-POM), lässt Maven die Effective POM berechnen, sucht neuere Versionen über die Repositories des Builds (Mirrors, Nexus/Artifactory, Zugangsdaten aus der `settings.xml`) und prüft die betroffenen Module mit `mvn test-compile`.
|
|
26
|
-
* **
|
|
26
|
+
* **Java / Gradle:** Findet die Builds des Repositories (Groovy- und Kotlin-DSL, Included Builds, `buildSrc`), fragt Gradle selbst, welche Abhängigkeiten gelten, sucht neuere Versionen über die Repositories des Builds (Mirrors, Nexus/Artifactory, Zugangsdaten), schreibt jede neue Version dorthin, wo ihr Text steht — Build-Skripte, `gradle.properties`, `ext`-Werte, der Version Catalog `gradle/libs.versions.toml`, der `plugins`-Block —, frischt Dependency Locks auf und prüft die betroffenen Projekte mit `testClasses`.
|
|
27
|
+
* **Live-Wechsel:** Ein Tastendruck auf **`[E]`** schaltet im laufenden Betrieb zwischen Node/npm-, Java/Maven-, Rust/Cargo- und Java/Gradle-Modulen um.
|
|
27
28
|
|
|
28
29
|
2. **🔍 Version gezielt heraussuchen (`[V]`):**
|
|
29
30
|
* Man muss nicht zwingend auf die `latest` Version aktualisieren: Taste **`[V]`** öffnet ein interaktives Such-Modal für das aktuell ausgewählte Paket.
|
|
@@ -71,12 +72,14 @@ Die URL der Registry allein entscheidet bewusst **nicht** über die Herkunft: In
|
|
|
71
72
|
* **npm:** Schließt der Versionsbereich einer Abhängigkeit die lokale Version eines Workspace-Pakets nicht ein, verlinkt npm das Workspace **nicht**, sondern installiert ein gleichnamiges Paket aus der Registry. Elevate bietet an, den Bereich anzugleichen (z. B. `^1.0.0` ➔ `^2.0.0`). Nach `npm install` prüft es die `package-lock.json`: Jede angeglichene Abhängigkeit muss `"link": true` sein, sonst wird das Update zurückgenommen. Bereiche, die npm immer verlinkt (`*`, `file:`, `workspace:`), bleiben unberührt.
|
|
72
73
|
* **pnpm:** pnpm verlinkt ein Workspace-Paket nur, wenn die Abhängigkeit mit dem `workspace:`-Protokoll geschrieben ist; ein einfacher Bereich wie `^1.0.0` wird aus der Registry aufgelöst — auch wenn die lokale Version ihn erfüllt. Elevate gleicht deshalb `workspace:^1.2.0` ➔ `workspace:^2.0.0` an (Protokoll und Präfix bleiben; `workspace:*`, `workspace:^`, `workspace:~` und `workspace:../lib` brauchen nichts) und führt einen einfachen Bereich auf ein Modul als *nicht verlinkt* (`not-linked`) auf, ohne den Namen je in einer Registry nachzuschlagen oder den Bereich umzuschreiben. Nach `pnpm install` liest es den Abschnitt `importers` der `pnpm-lock.yaml` (`lockfileVersion` 9.x): Jede angeglichene Abhängigkeit muss eine `version` mit `link:` haben, sonst wird das Update zurückgenommen.
|
|
73
74
|
* **Maven:** Hängt ein Modul mit abweichender Version von einem Modul *desselben Reactors* ab (z. B. `1.0.0`, während das Modul auf `1.1.0-SNAPSHOT` steht), bietet Elevate das Angleichen an. Verweise über `${project.version}` brauchen kein Angleichen.
|
|
75
|
+
* **Gradle:** Gradle ersetzt eine Abhängigkeit durch ein Projekt eines *Included Builds*, sobald Gruppe und Name passen, egal welche Version dasteht (`com.acme:lib:1.0.0` wird zum Projekt des Included Builds aufgelöst). Elevate gleicht eine solche Abhängigkeit an die Version des Projekts an und fragt den Namen nie in einem Repository ab; ein Included Build außerhalb des Repositories wird weder angeboten noch abgefragt. Ein Projekt desselben Builds wird nicht ersetzt, eine Abhängigkeit mit seinen Koordinaten ist also eine gewöhnliche.
|
|
74
76
|
* Der Release Channel gilt beim Angleichen nicht: Ziel ist die lokale Version — auch `-SNAPSHOT` —, weil die Module eines Repositorys zusammen gebaut und getestet werden.
|
|
75
77
|
|
|
76
78
|
### Private Registries & Dependency Confusion
|
|
77
79
|
|
|
78
80
|
* Interne Pakete werden nie in einer öffentlichen Registry abgefragt. Löst die Registry eines internen npm-Pakets zu `registry.npmjs.org` auf, wird es mit Begründung als *nicht angeboten* aufgeführt, statt abgefragt zu werden — genau diese Anfrage nach einem internen Namen nutzt ein Dependency-Confusion-Angriff aus.
|
|
79
|
-
* npm-Abfragen verwenden die npm-Konfiguration (`npm config`), Maven-Abfragen Maven selbst — Mirrors, private Repositories und Zugangsdaten gelten ohne eigene Elevate-Konfiguration, und Elevate fasst nie Zugangsdaten an.
|
|
81
|
+
* npm-Abfragen verwenden die npm-Konfiguration (`npm config`), Maven- und Gradle-Abfragen Maven bzw. Gradle selbst — Mirrors, private Repositories und Zugangsdaten gelten ohne eigene Elevate-Konfiguration, und Elevate fasst nie Zugangsdaten an.
|
|
82
|
+
* **Gradle:** Für ein internes Paket (`internalScopes`; eine Plugin-ID zählt wie eine Gruppe) lässt Elevate Gradle dessen Gruppe beim Abfragen mit einem Content-Filter (`excludeGroupByRegex`) von jedem bekannten öffentlichen Repository fernhalten (`repo.maven.apache.org`, `repo1.maven.org`, `plugins.gradle.org`, `dl.google.com`, `jitpack.io` und einige mehr), sodass keine Anfrage nach dem internen Namen sie erreicht; ein Artifactory oder Nexus der Firma gilt als privat, auch wenn es Maven Central spiegelt. Hat der Build dafür nur öffentliche Repositories, wird die Abhängigkeit als *nicht angeboten* aufgeführt, statt abgefragt zu werden. Zugangsdaten in einer Repository-URL verlassen den Scan nie.
|
|
80
83
|
|
|
81
84
|
### Wohin Maven-Versionen geschrieben werden
|
|
82
85
|
|
|
@@ -90,6 +93,7 @@ Jedes Update läuft als ein Ablauf: **Snapshot ➔ Schreiben & Installieren ➔
|
|
|
90
93
|
|
|
91
94
|
* **npm:** `npm ls` im Repository-Root (fehlende, ungültige oder unerfüllte Abhängigkeiten in allen Workspaces), sofern kein `postUpdateScript` gesetzt ist.
|
|
92
95
|
* **Maven:** `mvn test-compile -pl <geänderte Module> -amd` im Reactor — die geänderten Module *und alle Module, die von ihnen abhängen*. Eine Änderung an der Aggregator-POM baut den ganzen Reactor.
|
|
96
|
+
* **Gradle:** `testClasses` (sonst `assemble`) der Projekte, die die geänderten Dateien betreffen können: ein Projekt und jedes Projekt, das über `project(...)` von ihm abhängt; eine Änderung am Root-Projekt (Root-Skript, `gradle.properties`, Settings, `gradle/libs.versions.toml`) betrifft jedes Projekt. Tasks werden mit dem Projektpfad benannt (`:app:testClasses`), ein Modul eines Included Builds über den Namen seines Builds; ohne jeden Task läuft `help`, das den Build konfiguriert und `buildSrc` kompiliert.
|
|
93
97
|
|
|
94
98
|
### Cargo (Rust)
|
|
95
99
|
|
|
@@ -107,12 +111,71 @@ Elevate startet `cargo` aus dem `PATH` (`cargo metadata --no-deps`, `cargo updat
|
|
|
107
111
|
|
|
108
112
|
Elevate verwendet den Maven Wrapper des Projekts (`mvnw` / `mvnw.cmd`), sonst `mvn` aus dem `PATH`. Fehlt beides, bricht der Maven-Scan mit einer klaren Meldung ab, statt zu raten. Die Plugin-Versionen sind für reproduzierbare Ergebnisse festgelegt (`maven-help-plugin` 3.5.2, `versions-maven-plugin` 2.22.0) und lassen sich je Repository mit `mavenPlugins` in der `elevate.config.json` ersetzen (siehe [Maven-Plugin-Versionen](#maven-plugin-versionen)). Scans schreiben temporäre Dateien nur nach `target/.elevate-*` und entfernen sie danach.
|
|
109
113
|
|
|
114
|
+
### Wohin Gradle-Versionen geschrieben werden
|
|
115
|
+
|
|
116
|
+
Eine Gradle-Build-Datei ist ein Programm, deshalb parst Elevate sie nicht. Es fragt Gradle, was gilt — die Abhängigkeiten jedes Projekts mit der Version, die sie nach Ausführung aller Skripte haben — und sucht dann in den Dateien des Builds nach dem Text, der diese Version trägt. Eine Fundstelle zählt nur, wenn dort genau die von Gradle gemeldete Version steht. Was sich nicht sicher finden lässt, wird nicht geraten, sondern mit Begründung als *nicht angeboten* aufgeführt.
|
|
117
|
+
|
|
118
|
+
Der Text wird für die Abhängigkeiten eines Moduls (ein Projekt mit Build-Skript) in dieser Reihenfolge gesucht:
|
|
119
|
+
|
|
120
|
+
1. String- und Map-Notation im Build-Skript des Moduls selbst;
|
|
121
|
+
2. hat dieses Skript kein solches Literal, die Build-Skripte der Eltern-Projekte desselben Builds, das nächste zuerst (dort stehen `subprojects { }` und `allprojects { }`). Das erste Skript mit einem Treffer gewinnt, alle seine Treffer werden geschrieben;
|
|
122
|
+
3. ist die Version ein Name (`"g:a:$v"`, `version: v`): die Definition dieses Namens — zuerst `gradle.properties` (die Datei des Moduls, dann die des Builds), dann `def`-, `ext`- und `extra`-Werte im Skript des Moduls und seiner Eltern. Ein Wert, den Gradle überschreibt, eine mehrdeutige Definition oder eine, die kein einzelnes String-Literal ist, wird *nicht angeboten*;
|
|
123
|
+
4. markiert Gradle die Abhängigkeit als aus einem Version Catalog stammend: `gradle/libs.versions.toml` des Builds.
|
|
124
|
+
|
|
125
|
+
Nicht durchsucht werden Convention-Plugins in `buildSrc` oder einem Included Build, mit `apply from:` eingebundene Skripte, Init-Skripte und die `gradle.properties` des Benutzers. Beide DSLs werden nach denselben Regeln gelesen — außerhalb von Kommentaren ist jedes String-Literal ein Kandidat:
|
|
126
|
+
|
|
127
|
+
| Form | Groovy | Kotlin |
|
|
128
|
+
| :--- | :--- | :--- |
|
|
129
|
+
| String-Notation | `implementation 'g:a:1.0'`, `"g:a:1.0"`, `implementation('g:a:1.0')` | `implementation("g:a:1.0")` |
|
|
130
|
+
| Classifier, Extension | `'g:a:1.0:sources@jar'` (nur `1.0` ändert sich) | `"g:a:1.0:sources@jar"` |
|
|
131
|
+
| Map-Notation | `group: 'g', name: 'a', version: '1.0'` (beliebige Reihenfolge) | `group = "g", name = "a", version = "1.0"` |
|
|
132
|
+
| Name als Version | `"g:a:$v"`, `"g:a:${v}"`, `version: v` | `"g:a:$v"`, `"g:a:${v}"`, `version = v` |
|
|
133
|
+
| Plugin | `id 'x' version '1.0'`, `id('x') version('1.0')` | `id("x") version "1.0"`, `kotlin("jvm") version "1.9.20"` |
|
|
134
|
+
|
|
135
|
+
Eine Koordinate, die ein Modul mehrfach deklariert (in mehreren Konfigurationen, als Constraint, in einem Catalog), ist ein Kandidat, und die neue Version wird an jede Deklaration geschrieben. Ihr Scope ist der erste aus *prod*, *test* und *plugin* unter ihnen; eine Konfiguration ist eine Test-Konfiguration, wenn eines der Wörter ihres camelCase-Namens `test` ist. Platforms, Enforced Platforms und die Mitglieder eines Bundles werden wie Bibliotheken angeboten, ebenso Constraints (`dependencies { constraints { } }`). Abhängigkeiten, die sich eine Versions-Property oder einen Catalog-Eintrag teilen, werden markiert, und widersprüchliche Ziele für einen gemeinsamen Text werden abgelehnt. Edits ersetzen nur den Versionstext und verweigern eine Datei, in der er oder die Zeichen daneben sich seit dem Scan geändert haben (`1.0` wird zu `1.0.1`).
|
|
136
|
+
|
|
137
|
+
Als *nicht angeboten* aufgeführt wird:
|
|
138
|
+
|
|
139
|
+
| Grund | Wann |
|
|
140
|
+
| :--- | :--- |
|
|
141
|
+
| `version-constraint` | die Version ist ein Selektor oder trägt eine Einschränkung: `1.+`, `latest.release`, `[1.0,2.0)`, `strictly`, `reject`, `prefer` — eine geänderte Zahl würde die Bedeutung ändern |
|
|
142
|
+
| `declaration-mismatch` | der Text der Version lässt sich nicht sicher finden: berechnete Versionen, ein Convention-Plugin, ein `apply from:`-Skript, ein anderer Catalog als `gradle/libs.versions.toml`, ein von Gradle überschriebener Wert |
|
|
143
|
+
| `invalid-name` | ein externes Modul ohne Gruppe |
|
|
144
|
+
| `lookup-failed` | ein Repository-Fehler (Gradles eigene Worte, ohne Zugangsdaten) oder ein Build ohne deklariertes Repository |
|
|
145
|
+
| `private-on-public-registry` | ein internes Paket, dessen Repositories alle öffentlich sind |
|
|
146
|
+
|
|
147
|
+
### Version Catalogs
|
|
148
|
+
|
|
149
|
+
Gradle liest `gradle/libs.versions.toml` eines Builds als Catalog `libs`. Elevate liest die Datei als TOML und ordnet eine Abhängigkeit einem Eintrag über die Koordinaten zu: der Eintrag, dessen `module` (oder `group` und `name`) die der Abhängigkeit sind und dessen wirksame Version nach Auflösung von `version.ref` genau die von Gradle gemeldete ist. Der Versionstext wird an Ort und Stelle geändert — der `[versions]`-Schlüssel bei `version.ref`, sonst der Eintrag selbst (`"g:a:1.0"`, `version = "1.0"`, `version = { require = "1.0" }`) —, und Kommentare, Abstände, Reihenfolge, Zeilenenden und eine Byte-Order-Mark bleiben. Plugin-Einträge (`[plugins]`) werden genauso behandelt, Bundles enthalten nur Aliase und ihre Mitglieder werden als Bibliotheken angeboten, und ein `[versions]`-Schlüssel, auf den mehrere Bibliotheken verweisen, wird als gemeinsam markiert und einmal geschrieben. Einträge mit `strictly`, `prefer` oder `reject` werden als *nicht angeboten* aufgeführt. Gelesen wird nur die Datei des Builds selbst: in den Settings mit `versionCatalogs { }` deklarierte Catalogs nicht, und ein Included Build hat seine eigene Datei.
|
|
150
|
+
|
|
151
|
+
### Die Gradle-Läufe, die Elevate startet
|
|
152
|
+
|
|
153
|
+
Elevate parst Build-Dateien nie, um zu erfahren, was gilt, und kontaktiert nie selbst ein Repository. Es startet das Gradle des Builds — den Wrapper, der dem Modul am nächsten liegt, aufwärts gesucht, aber nie oberhalb des Repository-Roots (`sh ./gradlew`, unter Windows `.\gradlew.bat`), sonst `gradle` aus dem `PATH` — im Verzeichnis des Gradle-Builds des Moduls:
|
|
154
|
+
|
|
155
|
+
| Zweck | Befehl | Timeout |
|
|
156
|
+
| :--- | :--- | :--- |
|
|
157
|
+
| Build beschreiben (Projekte, deklarierte Abhängigkeiten, Repositories) | `-q -m --console=plain --no-configuration-cache -Delevate.mode=describe -Delevate.outDir=… -I <Skript> help` | 5 Min. |
|
|
158
|
+
| neuere Versionen abfragen | dasselbe mit `-Delevate.mode=lookup -Delevate.plan=…` | 5 Min. |
|
|
159
|
+
| Dependency Locks auffrischen | `-q --console=plain --no-configuration-cache :app:dependencies … --update-locks g:a,…` | 10 Min. |
|
|
160
|
+
| verifizieren | `-q --console=plain :app:testClasses …` | 30 Min. |
|
|
161
|
+
|
|
162
|
+
Die beiden Probe-Läufe nutzen ein kleines Groovy-Init-Skript, das Elevate mitbringt; die Antworten sind JSON-Dateien unter `.gradle/elevate-<id>/` des Builds, das nach dem Lauf in jedem Fall entfernt wird — die Standardausgabe trägt keine Antwort. `--no-configuration-cache` ist nötig: Bei aktiviertem Configuration Cache nutzt Gradle ihn im zweiten Lauf, und das Init-Skript würde nicht laufen. Weder `--daemon` noch `--no-daemon` wird übergeben: Die Läufe nutzen Gradle so, wie das Projekt es konfiguriert hat; ein kalter Daemon kostet einmal ein paar Sekunden, jeder weitere Lauf etwa eine. Ein Scan teilt sich je Gradle-Build einen Describe- und einen Lookup-Lauf, egal wie viele Module angefragt sind. Gradle älter als 7.6 wird mit einer Meldung abgelehnt.
|
|
163
|
+
|
|
164
|
+
### Dependency Locking und Dependency Verification
|
|
165
|
+
|
|
166
|
+
* **Locks.** Mit `dependencyLocking { lockAllConfigurations() }` liegt in jedem Projektverzeichnis eine `gradle.lockfile`, und eine angehobene Version lässt den Build scheitern, bis der Lock aufgefrischt ist. Nach dem Update einer Bibliothek frischt Elevate die Lock-Dateien des Root-Builds mit `gradle :app:dependencies :core:dependencies … --update-locks <Koordinaten>` auf — alle gemeinsam, denn ein veralteter Lock schlägt nicht immer fehl: Eine niedrigere deklarierte Version wird stillschweigend auf die gesperrte aufgelöst. Die Lock-Dateien gehören zum Snapshot, ein fehlgeschlagenes Auffrischen oder Verifizieren stellt sie wieder her. Locks von `buildSrc`, von Included Builds, vom `buildscript`-Classpath und von den Settings werden nicht aufgefrischt: Ein Update in einem Included Build oder in `buildSrc`, der Lock-Dateien hat, wird abgelehnt, bevor sich etwas ändert.
|
|
167
|
+
* **Dependency Verification.** Ein Build mit `gradle/verification-metadata.xml` verweigert die Artefakte einer neuen Version. Elevate erzeugt diese Datei nie neu (`--write-verification-metadata` würde die Prüfsumme dessen festhalten, was gerade geladen wurde, und ihren Zweck aushebeln): Das Update wird mit Gradles Meldung zurückgenommen, und du entscheidest.
|
|
168
|
+
|
|
169
|
+
### Voraussetzungen für Gradle
|
|
170
|
+
|
|
171
|
+
Ein JDK, das das Gradle des Builds unterstützt, Gradle 7.6 oder neuer und entweder ein Gradle Wrapper im Repository oder `gradle` im `PATH`; fehlt beides, bricht der Gradle-Scan mit einer klaren Meldung ab, statt zu raten. Auf welchem JDK eine Gradle-Version läuft, bestimmt Gradle (Gradle 7.6.6 läuft zum Beispiel nicht auf JDK 21). Die Integrationstests laufen gegen Gradle 7.6.6 (JDK 17), 8.14.3 und 9.8.1 (JDK 21). Nicht abgedeckt: das Aktualisieren des Gradle Wrappers selbst, Android- und Kotlin-Multiplatform-Builds (nicht verifiziert), Windows (spezifiziert, nicht verifiziert) und Plugins aus `settings.gradle`.
|
|
172
|
+
|
|
110
173
|
### Repository-Root
|
|
111
174
|
|
|
112
175
|
Elevate verhält sich gleich, egal wo im Repository es gestartet wird. Der Root wird so bestimmt:
|
|
113
176
|
|
|
114
177
|
1. Das nächste Verzeichnis (vom Startverzeichnis aufwärts) mit einer `elevate.config.json` ist der Root.
|
|
115
|
-
2. Sonst schlägt npm das nächste Verzeichnis vor, dessen `package.json` `workspaces` deklariert,
|
|
178
|
+
2. Sonst schlägt npm das nächste Verzeichnis vor, dessen `package.json` `workspaces` deklariert, Maven das obere Ende der zusammenhängenden POM-Kette (ein `<parent>`, der über `<relativePath>` gefunden wird, und jeder Aggregator, der das Projekt in `<modules>` aufführt) und Gradle das nächste Verzeichnis mit einer `settings.gradle(.kts)` (`buildSrc` gehört zum umgebenden Build, und ein Build, den eine äußere Settings-Datei mit einem literalen `includeBuild` einbindet, löst zu diesem äußeren Build auf). Der äußerste Vorschlag gewinnt.
|
|
116
179
|
3. Ohne jede Markierung ist das Startverzeichnis der Root.
|
|
117
180
|
|
|
118
181
|
Die Suche verlässt nie den Checkout der Versionsverwaltung: Sie endet im nächsten Verzeichnis, das einen `.git`-Eintrag enthält. Eine verirrte `package.json` oder `pom.xml` oberhalb des Repositorys wird daher nie für dessen Root gehalten. Manifeste, die sich nicht lesen lassen, werden übersprungen.
|
|
@@ -178,7 +241,7 @@ src/
|
|
|
178
241
|
│ ├── versions.ts # Erkennung von Vorabversionen & Versionshilfen
|
|
179
242
|
│ ├── ports.ts # Domain Ports (ModuleDiscoveryPort, RegistryPort, etc.)
|
|
180
243
|
│ ├── ecosystem-strategy.ts # Strategy Pattern: Plattform-agnostisches Interface
|
|
181
|
-
│ └── ecosystem-factory.ts # Factory Pattern: Liefert npm- oder
|
|
244
|
+
│ └── ecosystem-factory.ts # Factory Pattern: Liefert die npm-, Maven- oder Gradle-Strategie
|
|
182
245
|
│
|
|
183
246
|
├── adapters/ # 🔌 ADAPTERS (Konkrete Implementierungen)
|
|
184
247
|
│ ├── shared/ # 🧰 XML (positionsgenau), Prozesse, Snapshots, Pooling
|
|
@@ -198,18 +261,35 @@ src/
|
|
|
198
261
|
│ │ ├── npm-verifier.ts # npm ls / eigene Verifikation
|
|
199
262
|
│ │ └── npm-strategy.ts # NpmEcosystemStrategy
|
|
200
263
|
│ │
|
|
201
|
-
│
|
|
202
|
-
│
|
|
203
|
-
│
|
|
204
|
-
│
|
|
205
|
-
│
|
|
206
|
-
│
|
|
207
|
-
│
|
|
208
|
-
│
|
|
209
|
-
│
|
|
210
|
-
│
|
|
211
|
-
│
|
|
212
|
-
│
|
|
264
|
+
│ ├── maven/ # ☕ Java / Maven Adapter
|
|
265
|
+
│ │ ├── maven-command.ts # Aufruf über Maven Wrapper / mvn
|
|
266
|
+
│ │ ├── maven-pom.ts # Rohes POM-Modell mit editierbaren Textbereichen
|
|
267
|
+
│ │ ├── maven-project.ts # Alle POMs des Repos, Parent-Ketten, Reactors
|
|
268
|
+
│ │ ├── maven-discovery.ts # Module inkl. Root-POM, Versionen, Aggregator
|
|
269
|
+
│ │ ├── maven-resolution.ts # Effective POM & Report des versions-maven-plugin
|
|
270
|
+
│ │ ├── maven-locator.ts # Findet die Stelle, an der eine Version steht
|
|
271
|
+
│ │ ├── maven-scanner.ts # Herkunft, Angleichen, Update-Kandidaten
|
|
272
|
+
│ │ ├── maven-registry.ts # `elevate versions` über Maven (jeder Nexus/Artifactory)
|
|
273
|
+
│ │ ├── maven-updater.ts # Formatierungserhaltende POM-Änderungen
|
|
274
|
+
│ │ ├── maven-verifier.ts # mvn test-compile -pl … -amd
|
|
275
|
+
│ │ └── maven-strategy.ts # MavenEcosystemStrategy
|
|
276
|
+
│
|
|
277
|
+
│ └── gradle/ # 🐘 Java / Gradle Adapters
|
|
278
|
+
│ ├── gradle-command.ts # Aufruf über Wrapper / gradle, Gradles eigene Fehlertexte
|
|
279
|
+
│ ├── gradle-init-script.ts # Das Groovy-Init-Skript, das Describe-/Lookup-Läufe beantwortet
|
|
280
|
+
│ ├── gradle-probe.ts # runDescribe / runLookup und das Scratch-Verzeichnis
|
|
281
|
+
│ ├── gradle-discovery.ts # Build-Verzeichnisse, Repository-Root, Module aus den beschriebenen Builds
|
|
282
|
+
│ ├── gradle-versions.ts # Gradles Versionsreihenfolge
|
|
283
|
+
│ ├── gradle-repositories.ts # Wirksame Repositories, öffentliche Hosts, Lookup-Plan, Schutz interner Gruppen
|
|
284
|
+
│ ├── gradle-text.ts # String-Literale außerhalb von Kommentaren, formatierungserhaltende Edits
|
|
285
|
+
│ ├── gradle-catalog.ts # gradle/libs.versions.toml: Einträge und der Text einer Version
|
|
286
|
+
│ ├── gradle-locator.ts # Findet, wo eine Version deklariert ist
|
|
287
|
+
│ ├── gradle-scanner.ts # Herkunft, Angleichen an Included Builds, Update-Kandidaten
|
|
288
|
+
│ ├── gradle-registry.ts # `elevate versions` über Gradle (jeder Nexus/Artifactory)
|
|
289
|
+
│ ├── gradle-locks.ts # gradle.lockfile finden und --update-locks
|
|
290
|
+
│ ├── gradle-updater.ts # Formatierungserhaltende Edits, Lock-Auffrischung
|
|
291
|
+
│ ├── gradle-verifier.ts # testClasses / assemble der betroffenen Projekte
|
|
292
|
+
│ └── gradle-strategy.ts # GradleEcosystemStrategy
|
|
213
293
|
│
|
|
214
294
|
├── application/ # 🧭 ANWENDUNGSFÄLLE für TUI, CLI und MCP
|
|
215
295
|
│ ├── scan.ts # Scan-Kontext, Modulsuche, JSON-Ausgabe
|
|
@@ -283,7 +363,7 @@ node tools/updater/elevate/index.mjs update --module=apps/e2e-cockpit --packages
|
|
|
283
363
|
node tools/updater/elevate/index.mjs update --module=apps/web --all --keep-on-failure
|
|
284
364
|
```
|
|
285
365
|
|
|
286
|
-
`scan --json` liefert je Modul die `updates` (mit `action`, `origin` und bei Maven `declaredIn`) und die übersprungenen Abhängigkeiten unter `skipped` mit `reason`. `update` endet mit Exit-Code `2`, wenn das Update fehlschlug und zurückgenommen wurde.
|
|
366
|
+
`scan --json` liefert je Modul die `updates` (mit `action`, `origin` und bei Maven und Gradle `declaredIn`, bei Gradle außerdem `alsoDeclaredIn`, wenn eine Version an mehreren Stellen steht) und die übersprungenen Abhängigkeiten unter `skipped` mit `reason`. `update` endet mit Exit-Code `2`, wenn das Update fehlschlug und zurückgenommen wurde.
|
|
287
367
|
|
|
288
368
|
### 2. Model Context Protocol (MCP) Server
|
|
289
369
|
|
|
@@ -307,7 +387,7 @@ In der MCP-Konfiguration hinterlegen (z. B. `claude_desktop_config.json` oder An
|
|
|
307
387
|
#### Verfügbare MCP-Tools für LLMs:
|
|
308
388
|
| Tool | Funktion |
|
|
309
389
|
| :--- | :--- |
|
|
310
|
-
| `elevate_discover_modules` | Erkennt alle Monorepo-Module und Workspaces für npm oder
|
|
390
|
+
| `elevate_discover_modules` | Erkennt alle Monorepo-Module und Workspaces für npm, Maven, Cargo oder Gradle (Gradle-Module nennen die Art ihres Builds) |
|
|
311
391
|
| `elevate_scan` | Scannt ein Modul (oder alle Module) nach Updates und anzugleichenden internen Abhängigkeiten; nennt übersprungene Abhängigkeiten mit Grund |
|
|
312
392
|
| `elevate_get_versions` | Ruft die Versionshistorie aus der Registry ab (keine öffentliche Abfrage interner Pakete) |
|
|
313
393
|
| `elevate_apply_updates` | Wendet Updates mit Verifikation, Major-Guardrail und Rücknahme an (`keepOnFailure` optional) |
|
|
@@ -319,7 +399,7 @@ In der MCP-Konfiguration hinterlegen (z. B. `claude_desktop_config.json` oder An
|
|
|
319
399
|
|
|
320
400
|
| Taste | Aktion |
|
|
321
401
|
| :--- | :--- |
|
|
322
|
-
| **`E`** | **Ökosystem umschalten (📦 Node/npm
|
|
402
|
+
| **`E`** | **Ökosystem umschalten (📦 Node/npm → ☕ Java/Maven → 🦀 Rust/Cargo → 🐘 Java/Gradle)** |
|
|
323
403
|
| **`W`** | Modul- / Workspace-Auswahl öffnen |
|
|
324
404
|
| **`V`** | **Version heraussuchen (Interaktiver Such- & Filterdialog)** |
|
|
325
405
|
| **`L`** | Sprache umschalten (Deutsch ⇄ English) |
|
|
@@ -352,9 +432,9 @@ Im Wurzelverzeichnis deines Repositories kann optional eine `elevate.config.json
|
|
|
352
432
|
* **`author`:** Optionaler Name, der oben rechts im Header erscheint.
|
|
353
433
|
* **`channel`:** `"stable"` (Standard, schließt Betas/RCs aus) oder `"all"` (zeigt auch Vorabversionen).
|
|
354
434
|
* **`locale`:** `"de"` (Deutsch), `"en"` (Englisch) oder `"auto"` (automatische Erkennung).
|
|
355
|
-
* **`internalScopes`:** Interne npm-Scopes und Maven-groupId-Präfixe. `@my-org` trifft `@my-org/*`; `com.mycompany` trifft `com.mycompany` und `com.mycompany.*` (nicht `com.mycompanyx`). Passende Pakete werden nur in privaten Registries abgefragt. *Früher `excludeScopes`; der alte Name wird weiter gelesen und als veraltet gemeldet.*
|
|
435
|
+
* **`internalScopes`:** Interne npm-Scopes und Maven-/Gradle-groupId-Präfixe (bei Gradle auch Plugin-IDs). `@my-org` trifft `@my-org/*`; `com.mycompany` trifft `com.mycompany` und `com.mycompany.*` (nicht `com.mycompanyx`). Passende Pakete werden nur in privaten Registries abgefragt. *Früher `excludeScopes`; der alte Name wird weiter gelesen und als veraltet gemeldet.*
|
|
356
436
|
* **`mavenPlugins`:** Optionale Versionen der Maven-Plugins, die Elevate startet: `help` (`maven-help-plugin`, Standard `3.5.2`) und `versions` (`versions-maven-plugin`, Standard `2.22.0`). Nutze es, wenn dein Repository-Manager die Standardversionen nicht anbietet. Ungültige Werte fallen mit einer Warnung auf den Standard zurück.
|
|
357
|
-
* **`postUpdateScript`:** Optionaler Befehl, der die Standard-Verifikation (`npm ls` / `mvn test-compile`) ersetzt. Läuft im Repository-Root (npm) bzw. im
|
|
437
|
+
* **`postUpdateScript`:** Optionaler Befehl, der die Standard-Verifikation (`npm ls` / `mvn test-compile`) ersetzt. Läuft im Repository-Root (npm), im Modulverzeichnis (Maven) bzw. im Verzeichnis des Gradle-Builds des Moduls (Gradle).
|
|
358
438
|
|
|
359
439
|
---
|
|
360
440
|
|
package/docs/en.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
## 🌟 Overview
|
|
9
9
|
|
|
10
|
-
**Elevate** is an interactive terminal dashboard (TUI) for safe, selective, and transparent dependency management across **polyglot monorepos** (Node/npm & Java/
|
|
10
|
+
**Elevate** is an interactive terminal dashboard (TUI) for safe, selective, and transparent dependency management across **polyglot monorepos** (Node/npm, Java/Maven, Rust/Cargo & Java/Gradle) and single-package projects.
|
|
11
11
|
|
|
12
12
|
* **Feather Identity (`🪶`) & Orange Brand (`#FF8800`):** Clean, modern, and readable in any terminal.
|
|
13
|
-
* **Polyglot Architecture:** Seamlessly manages frontend workspaces (`package.json` with npm workspaces) and backend modules (`pom.xml` with Maven).
|
|
13
|
+
* **Polyglot Architecture:** Seamlessly manages frontend workspaces (`package.json` with npm workspaces) and backend modules (`pom.xml` with Maven, `build.gradle` with Gradle, `Cargo.toml` with Cargo).
|
|
14
14
|
* **Release Channels:** Filters out pre-releases (Alpha, Beta, RC, Milestone, Snapshot) by default, suggesting only battle-tested production releases.
|
|
15
15
|
* **Animated Companion ("Pip" 🐣):** A delightful chicken mascot that reacts to actions and keeps you company in the terminal.
|
|
16
16
|
* **Bilingual i18n:** Toggle on the fly between English and German with the **`[L]`** key.
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
|
|
20
20
|
## ✨ Features & Highlights
|
|
21
21
|
|
|
22
|
-
1. **🌐 Polyglot Monorepo Support (npm, pnpm &
|
|
22
|
+
1. **🌐 Polyglot Monorepo Support (npm, pnpm, Maven, Cargo & Gradle):**
|
|
23
23
|
* **Node / npm:** Resolves workspaces exactly like npm (glob patterns such as `packages/**` included), calculates SemVer diffs, updates `package.json` (`dependencies`, `devDependencies`, `optionalDependencies`), runs `npm install` and checks the lockfile. **Node / pnpm** (9 – 12) works the same way for pnpm repositories: workspaces from `pnpm-workspace.yaml`, the `workspace:` protocol, `catalog:` entries, `pnpm install` and a lockfile check. Repositories managed by Yarn or Bun are refused.
|
|
24
24
|
* **Java / Maven:** Finds every `pom.xml` (including the root POM), lets Maven compute the effective POM, looks up newer versions through the build's own repositories (mirrors, Nexus/Artifactory, credentials from `settings.xml`) and verifies the affected modules with `mvn test-compile`.
|
|
25
|
-
* **
|
|
25
|
+
* **Java / Gradle:** Finds the builds of the repository (Groovy and Kotlin DSL, included builds, `buildSrc`), asks Gradle itself which dependencies apply, looks up newer versions through the build's own repositories (mirrors, Nexus/Artifactory, credentials), writes each new version where its text is found — build scripts, `gradle.properties`, `ext` values, the version catalog `gradle/libs.versions.toml`, the `plugins` block — refreshes dependency locks and verifies the affected projects with `testClasses`.
|
|
26
|
+
* **Runtime Switch:** Press **`[E]`** anytime to switch between Node/npm, Java/Maven, Rust/Cargo and Java/Gradle modules.
|
|
26
27
|
|
|
27
28
|
2. **🔍 Pick a Specific Version (`[V]`):**
|
|
28
29
|
* You aren't restricted to upgrading only to `latest`: pressing **`[V]`** opens an interactive modal to browse and select any published version for the focused package.
|
|
@@ -70,12 +71,14 @@ The registry URL alone is deliberately **not** used to decide the origin: in mos
|
|
|
70
71
|
* **npm:** If a dependency's range does not include the local version of a workspace package, npm does **not** link the workspace — it installs a package with the same name from the registry. Elevate offers to align the range (e.g. `^1.0.0` ➔ `^2.0.0`). After `npm install` it checks `package-lock.json`: every aligned dependency must be `"link": true`, otherwise the update is rolled back. Ranges that npm always links (`*`, `file:`, `workspace:`) are left alone.
|
|
71
72
|
* **pnpm:** pnpm links a workspace package only when the dependency is written with the `workspace:` protocol; a plain range such as `^1.0.0` is resolved from the registry, even if the local version satisfies it. Elevate therefore aligns `workspace:^1.2.0` ➔ `workspace:^2.0.0` (the protocol and the prefix are kept; `workspace:*`, `workspace:^`, `workspace:~` and `workspace:../lib` need nothing) and lists a plain range on a module as *not linked* without ever looking the name up in a registry or rewriting it. After `pnpm install` it reads the `importers` section of `pnpm-lock.yaml` (`lockfileVersion` 9.x): every aligned dependency must have a `version` starting with `link:`, otherwise the update is rolled back.
|
|
72
73
|
* **Maven:** If a module depends on a module of the *same reactor* with a different version (e.g. `1.0.0` while the module is at `1.1.0-SNAPSHOT`), Elevate offers to align it. `${project.version}` references need no alignment.
|
|
74
|
+
* **Gradle:** Gradle substitutes a dependency by a project of an *included build* whenever group and name match, whatever version is written (`com.acme:lib:1.0.0` resolves to the included build's project). Elevate aligns such a dependency to the project's version and never looks the name up in a repository; an included build outside the repository is neither offered nor looked up. A project of the *same* build is not substituted, so a dependency with its coordinates is an ordinary one.
|
|
73
75
|
* The release channel does not apply to alignment: the local version — including `-SNAPSHOT` — is the target, because modules of one repository are built and tested together.
|
|
74
76
|
|
|
75
77
|
### Private registries & dependency confusion
|
|
76
78
|
|
|
77
79
|
* Internal packages are never looked up on a public registry. If the registry for an internal npm package resolves to `registry.npmjs.org`, it is listed as *not offered* with the reason, instead of being queried — asking a public registry about an internal name is exactly what a dependency-confusion attack exploits.
|
|
78
|
-
* npm lookups use your npm configuration (`npm config`), Maven lookups use Maven itself — mirrors, private repositories and credentials apply without any Elevate-specific configuration, and Elevate never handles credentials.
|
|
80
|
+
* npm lookups use your npm configuration (`npm config`), Maven and Gradle lookups use Maven or Gradle itself — mirrors, private repositories and credentials apply without any Elevate-specific configuration, and Elevate never handles credentials.
|
|
81
|
+
* **Gradle:** for an internal package (`internalScopes`; a plugin id counts like a group) Elevate has Gradle keep its group away from every well-known public repository (`repo.maven.apache.org`, `repo1.maven.org`, `plugins.gradle.org`, `dl.google.com`, `jitpack.io` and a few more) during the lookup with a content filter (`excludeGroupByRegex`), so no request for the internal name reaches them; a company's Artifactory or Nexus counts as private even when it mirrors Maven Central. If the build has only public repositories for it, the dependency is listed as *not offered* instead of being looked up. Credentials in a repository URL never leave the scan.
|
|
79
82
|
|
|
80
83
|
### Where Maven versions are written
|
|
81
84
|
|
|
@@ -89,6 +92,7 @@ Every update runs as one workflow: **snapshot ➔ write & install ➔ integrity
|
|
|
89
92
|
|
|
90
93
|
* **npm:** `npm ls` at the repository root (missing, invalid or unmet dependencies across all workspaces), unless `postUpdateScript` is set.
|
|
91
94
|
* **Maven:** `mvn test-compile -pl <changed modules> -amd` in the reactor — the changed modules *and every module depending on them*. A change to the aggregator POM rebuilds the whole reactor.
|
|
95
|
+
* **Gradle:** `testClasses` (else `assemble`) of the projects the changed files can affect: a project and every project that depends on it through `project(...)`; a change to the root project (root script, `gradle.properties`, settings, `gradle/libs.versions.toml`) affects every project. Tasks are named by project path (`:app:testClasses`), a module of an included build through the name of its build; without any task the run is `help`, which configures the build and compiles `buildSrc`.
|
|
92
96
|
|
|
93
97
|
### Cargo (Rust)
|
|
94
98
|
|
|
@@ -106,12 +110,71 @@ Elevate runs `cargo` from the `PATH` (`cargo metadata --no-deps`, `cargo update`
|
|
|
106
110
|
|
|
107
111
|
Elevate uses the project's Maven Wrapper (`mvnw` / `mvnw.cmd`) when present, otherwise `mvn` on the `PATH`. Without either, Maven scans fail with a clear message instead of guessing. Plugin versions are pinned for reproducible results (`maven-help-plugin` 3.5.2, `versions-maven-plugin` 2.22.0) and can be replaced per repository with `mavenPlugins` in `elevate.config.json` (see [Maven plugin versions](#maven-plugin-versions)). Scans write temporary files only to `target/.elevate-*` and remove them afterwards.
|
|
108
112
|
|
|
113
|
+
### Where Gradle versions are written
|
|
114
|
+
|
|
115
|
+
A Gradle build file is a program, so Elevate does not parse it. It asks Gradle what applies — the dependencies every project declares, with the version each one has after all scripts have run — and then looks in the files of the build for the text that carries that version. A location counts only if the text there is exactly the version Gradle reports. What cannot be located with certainty is not guessed: it is listed as *not offered* with the reason.
|
|
116
|
+
|
|
117
|
+
The text is searched in this order, for the dependencies of a module (a project with a build script):
|
|
118
|
+
|
|
119
|
+
1. string and map notation in the module's own build script;
|
|
120
|
+
2. when that script has no such literal, the build scripts of the parent projects of the same build, nearest first (`subprojects { }` and `allprojects { }` live there). The first script with a match wins and all its matches are written;
|
|
121
|
+
3. when the version is a name (`"g:a:$v"`, `version: v`): the definition of that name — `gradle.properties` first (the module's own file, then the build's), then `def`, `ext` and `extra` values of the module's script and its parents. A value that Gradle overrides, an ambiguous definition or one that is not a single string literal is *not offered*;
|
|
122
|
+
4. when Gradle marks the dependency as coming from a version catalog: `gradle/libs.versions.toml` of the build.
|
|
123
|
+
|
|
124
|
+
Not searched: convention plugins in `buildSrc` or an included build, scripts applied with `apply from:`, init scripts and the user's `gradle.properties`. Both DSLs are read by the same rules — outside comments, every string literal is a candidate:
|
|
125
|
+
|
|
126
|
+
| Form | Groovy | Kotlin |
|
|
127
|
+
| :--- | :--- | :--- |
|
|
128
|
+
| string notation | `implementation 'g:a:1.0'`, `"g:a:1.0"`, `implementation('g:a:1.0')` | `implementation("g:a:1.0")` |
|
|
129
|
+
| classifier, extension | `'g:a:1.0:sources@jar'` (only `1.0` changes) | `"g:a:1.0:sources@jar"` |
|
|
130
|
+
| map notation | `group: 'g', name: 'a', version: '1.0'` (any order) | `group = "g", name = "a", version = "1.0"` |
|
|
131
|
+
| name as the version | `"g:a:$v"`, `"g:a:${v}"`, `version: v` | `"g:a:$v"`, `"g:a:${v}"`, `version = v` |
|
|
132
|
+
| plugin | `id 'x' version '1.0'`, `id('x') version('1.0')` | `id("x") version "1.0"`, `kotlin("jvm") version "1.9.20"` |
|
|
133
|
+
|
|
134
|
+
A coordinate that a module declares several times (in several configurations, as a constraint, in a catalog) is one candidate and the new version is written to every declaration. Its scope is the first of *prod*, *test* and *plugin* among them; a configuration is a test configuration when one of the words of its camelCase name is `test`. Platforms, enforced platforms and the members of a bundle are offered like libraries; constraints (`dependencies { constraints { } }`) are offered too. Dependencies that share a version property or a catalog entry are marked, and conflicting targets for a shared text are rejected. Edits replace only the version text and refuse a file in which it, or the characters around it, changed since the scan (`1.0` turning into `1.0.1`).
|
|
135
|
+
|
|
136
|
+
What is listed as *not offered*:
|
|
137
|
+
|
|
138
|
+
| Reason | When |
|
|
139
|
+
| :--- | :--- |
|
|
140
|
+
| `version-constraint` | the version is a selector or carries a constraint: `1.+`, `latest.release`, `[1.0,2.0)`, `strictly`, `reject`, `prefer` — changing one number would change its meaning |
|
|
141
|
+
| `declaration-mismatch` | the text of the version cannot be located with certainty: computed versions, a convention plugin, an `apply from:` script, a catalog other than `gradle/libs.versions.toml`, a value Gradle overrides |
|
|
142
|
+
| `invalid-name` | an external module without a group |
|
|
143
|
+
| `lookup-failed` | a repository error (Gradle's own words, without credentials), or a build that declares no repository |
|
|
144
|
+
| `private-on-public-registry` | an internal package whose repositories are all public |
|
|
145
|
+
|
|
146
|
+
### Version catalogs
|
|
147
|
+
|
|
148
|
+
Gradle reads `gradle/libs.versions.toml` of a build as the catalog `libs`. Elevate reads it as TOML and matches a dependency to an entry by coordinates: the entry whose `module` (or `group` and `name`) is the dependency's and whose effective version, after resolving `version.ref`, is exactly the version Gradle reports. The text of the version is edited in place — the `[versions]` key for `version.ref`, otherwise the entry itself (`"g:a:1.0"`, `version = "1.0"`, `version = { require = "1.0" }`) — and comments, spacing, order, line endings and a byte order mark stay. Plugin entries (`[plugins]`) are handled the same way, bundles hold aliases only and their members are offered as libraries, and a `[versions]` key that several libraries refer to is shown as shared and written once. Entries with `strictly`, `prefer` or `reject` are listed as *not offered*. Only the file of the build itself is read: catalogs declared in the settings with `versionCatalogs { }` are not, and an included build has its own file.
|
|
149
|
+
|
|
150
|
+
### The Gradle runs Elevate makes
|
|
151
|
+
|
|
152
|
+
Elevate never parses build files for what applies and never contacts a repository itself. It runs the build's own Gradle — the wrapper closest to the module, searching upwards but never above the repository root (`sh ./gradlew`, on Windows `.\gradlew.bat`), otherwise `gradle` on the `PATH` — in the directory of the module's Gradle build:
|
|
153
|
+
|
|
154
|
+
| Purpose | Command | Timeout |
|
|
155
|
+
| :--- | :--- | :--- |
|
|
156
|
+
| describe the build (projects, declared dependencies, repositories) | `-q -m --console=plain --no-configuration-cache -Delevate.mode=describe -Delevate.outDir=… -I <script> help` | 5 min |
|
|
157
|
+
| look up newer versions | the same with `-Delevate.mode=lookup -Delevate.plan=…` | 5 min |
|
|
158
|
+
| refresh dependency locks | `-q --console=plain --no-configuration-cache :app:dependencies … --update-locks g:a,…` | 10 min |
|
|
159
|
+
| verify | `-q --console=plain :app:testClasses …` | 30 min |
|
|
160
|
+
|
|
161
|
+
The two probe runs use a small Groovy init script that Elevate carries; the answers are JSON files below `.gradle/elevate-<id>/` of the build, which is removed when the run ends, whatever the outcome — standard output carries no answer. `--no-configuration-cache` is required: with the configuration cache enabled Gradle reuses it on the second run and the init script would not run. Neither `--daemon` nor `--no-daemon` is passed: the runs use Gradle as the project configured it, so a cold daemon costs a few seconds once and every further run about a second. A scan shares one describe run and one lookup run per Gradle build, however many modules are requested. Gradle older than 7.6 is refused with a message.
|
|
162
|
+
|
|
163
|
+
### Dependency locking and dependency verification
|
|
164
|
+
|
|
165
|
+
* **Locks.** With `dependencyLocking { lockAllConfigurations() }` a `gradle.lockfile` sits in each project directory, and raising a declared version makes the build fail until the lock is refreshed. After an update of a library Elevate refreshes the lock files of the root build with `gradle :app:dependencies :core:dependencies … --update-locks <coordinates>` — all of them together, because a stale lock does not always fail: a lower declared version is silently resolved down to the locked one. The lock files are part of the snapshot, so a failed refresh or verification restores them. Locks of `buildSrc`, of included builds, of the `buildscript` classpath and of the settings are not refreshed: an update in an included build or `buildSrc` that has lock files is refused before anything changes.
|
|
166
|
+
* **Dependency verification.** A build with `gradle/verification-metadata.xml` refuses the artifacts of a new version. Elevate never regenerates that file (`--write-verification-metadata` would record the checksum of whatever was downloaded and defeat its purpose): the update is rolled back with Gradle's message and you decide.
|
|
167
|
+
|
|
168
|
+
### Requirements for Gradle
|
|
169
|
+
|
|
170
|
+
A JDK that the build's Gradle supports, Gradle 7.6 or newer, and either a Gradle Wrapper in the repository or `gradle` on the `PATH`; without either, Gradle scans fail with a clear message instead of guessing. Which JDK a Gradle version runs on is Gradle's to state (for example Gradle 7.6.6 does not run on JDK 21). The integration tests run against Gradle 7.6.6 (JDK 17), 8.14.3 and 9.8.1 (JDK 21). Not covered: updating the Gradle Wrapper itself, Android and Kotlin Multiplatform builds (not verified), Windows (specified, not verified) and `settings.gradle` plugins.
|
|
171
|
+
|
|
109
172
|
### Repository root
|
|
110
173
|
|
|
111
174
|
Elevate works the same wherever in the repository it is started. The root is found as follows:
|
|
112
175
|
|
|
113
176
|
1. The nearest directory (from the start directory upwards) with an `elevate.config.json` is the root.
|
|
114
|
-
2. Otherwise npm proposes the nearest directory whose `package.json` declares `workspaces`,
|
|
177
|
+
2. Otherwise npm proposes the nearest directory whose `package.json` declares `workspaces`, Maven proposes the top of the connected POM chain (a `<parent>` found through `<relativePath>` and any aggregator that lists the project in `<modules>`), and Gradle proposes the nearest directory with a `settings.gradle(.kts)` (`buildSrc` belongs to the build around it, and a build that an outer settings file includes with a literal `includeBuild` resolves to that outer build). The outermost proposal wins.
|
|
115
178
|
3. Without any marker the start directory is the root.
|
|
116
179
|
|
|
117
180
|
The search never leaves the version-control checkout: it stops at the nearest directory that contains a `.git` entry, so a stray `package.json` or `pom.xml` somewhere above the repository is never mistaken for its root. Manifests that cannot be parsed are skipped.
|
|
@@ -177,7 +240,7 @@ src/
|
|
|
177
240
|
│ ├── versions.ts # Pre-release detection & version helpers
|
|
178
241
|
│ ├── ports.ts # Domain Ports (ModuleDiscoveryPort, RegistryPort, etc.)
|
|
179
242
|
│ ├── ecosystem-strategy.ts # Strategy Pattern: Platform-agnostic interface
|
|
180
|
-
│ └── ecosystem-factory.ts # Factory Pattern: Resolves npm or
|
|
243
|
+
│ └── ecosystem-factory.ts # Factory Pattern: Resolves the npm, Maven or Gradle strategy
|
|
181
244
|
│
|
|
182
245
|
├── adapters/ # 🔌 ADAPTERS (Concrete port implementations)
|
|
183
246
|
│ ├── shared/ # 🧰 XML (position-aware), processes, snapshots, pooling
|
|
@@ -198,18 +261,35 @@ src/
|
|
|
198
261
|
│ │ ├── npm-verifier.ts # npm ls / custom verification
|
|
199
262
|
│ │ └── npm-strategy.ts # NpmEcosystemStrategy
|
|
200
263
|
│ │
|
|
201
|
-
│
|
|
202
|
-
│
|
|
203
|
-
│
|
|
204
|
-
│
|
|
205
|
-
│
|
|
206
|
-
│
|
|
207
|
-
│
|
|
208
|
-
│
|
|
209
|
-
│
|
|
210
|
-
│
|
|
211
|
-
│
|
|
212
|
-
│
|
|
264
|
+
│ ├── maven/ # ☕ Java / Maven Adapters
|
|
265
|
+
│ │ ├── maven-command.ts # Maven Wrapper / mvn invocation
|
|
266
|
+
│ │ ├── maven-pom.ts # Raw POM model with editable element ranges
|
|
267
|
+
│ │ ├── maven-project.ts # All POMs of the repo, parent chains, reactors
|
|
268
|
+
│ │ ├── maven-discovery.ts # Modules incl. root POM, versions, aggregator
|
|
269
|
+
│ │ ├── maven-resolution.ts # Effective POM & versions-maven-plugin report
|
|
270
|
+
│ │ ├── maven-locator.ts # Finds where a version is declared
|
|
271
|
+
│ │ ├── maven-scanner.ts # Origins, alignment, update candidates
|
|
272
|
+
│ │ ├── maven-registry.ts # `elevate versions` via Maven (any Nexus/Artifactory)
|
|
273
|
+
│ │ ├── maven-updater.ts # Formatting-preserving POM edits
|
|
274
|
+
│ │ ├── maven-verifier.ts # mvn test-compile -pl … -amd
|
|
275
|
+
│ │ └── maven-strategy.ts # MavenEcosystemStrategy
|
|
276
|
+
│
|
|
277
|
+
│ └── gradle/ # 🐘 Java / Gradle Adapters
|
|
278
|
+
│ ├── gradle-command.ts # Wrapper / gradle invocation, Gradle's own error words
|
|
279
|
+
│ ├── gradle-init-script.ts # The Groovy init script that answers describe / lookup runs
|
|
280
|
+
│ ├── gradle-probe.ts # runDescribe / runLookup and the scratch directory
|
|
281
|
+
│ ├── gradle-discovery.ts # Build directories, repository root, modules from the described builds
|
|
282
|
+
│ ├── gradle-versions.ts # Gradle's version order
|
|
283
|
+
│ ├── gradle-repositories.ts # Effective repositories, public hosts, lookup plan, internal-group guard
|
|
284
|
+
│ ├── gradle-text.ts # String literals outside comments, formatting-preserving edits
|
|
285
|
+
│ ├── gradle-catalog.ts # gradle/libs.versions.toml: entries and the text of a version
|
|
286
|
+
│ ├── gradle-locator.ts # Finds where a version is declared
|
|
287
|
+
│ ├── gradle-scanner.ts # Origins, included-build alignment, update candidates
|
|
288
|
+
│ ├── gradle-registry.ts # `elevate versions` via Gradle (any Nexus/Artifactory)
|
|
289
|
+
│ ├── gradle-locks.ts # gradle.lockfile discovery and --update-locks
|
|
290
|
+
│ ├── gradle-updater.ts # Formatting-preserving edits, lock refresh
|
|
291
|
+
│ ├── gradle-verifier.ts # testClasses / assemble of the affected projects
|
|
292
|
+
│ └── gradle-strategy.ts # GradleEcosystemStrategy
|
|
213
293
|
│
|
|
214
294
|
├── application/ # 🧭 USE CASES shared by TUI, CLI and MCP
|
|
215
295
|
│ ├── scan.ts # Scan context, module lookup, JSON output
|
|
@@ -285,7 +365,7 @@ node tools/updater/elevate/index.mjs update --module=apps/e2e-cockpit --packages
|
|
|
285
365
|
node tools/updater/elevate/index.mjs update --module=apps/web --all --keep-on-failure
|
|
286
366
|
```
|
|
287
367
|
|
|
288
|
-
`scan --json` lists, per module, the `updates` (with `action`, `origin` and — for Maven — `declaredIn`) and the `skipped` dependencies with their `reason`. `update` exits with `2` when the update failed and was rolled back.
|
|
368
|
+
`scan --json` lists, per module, the `updates` (with `action`, `origin` and — for Maven and Gradle — `declaredIn`, plus `alsoDeclaredIn` when a Gradle version is written in several places) and the `skipped` dependencies with their `reason`. `update` exits with `2` when the update failed and was rolled back.
|
|
289
369
|
|
|
290
370
|
### 2. Model Context Protocol (MCP) Server
|
|
291
371
|
|
|
@@ -309,7 +389,7 @@ Register it in your agent's MCP settings (e.g., `claude_desktop_config.json` or
|
|
|
309
389
|
#### Available MCP Tools for LLMs:
|
|
310
390
|
| Tool | Purpose |
|
|
311
391
|
| :--- | :--- |
|
|
312
|
-
| `elevate_discover_modules` | Discovers all repository modules and workspaces for npm or
|
|
392
|
+
| `elevate_discover_modules` | Discovers all repository modules and workspaces for npm, Maven, Cargo or Gradle (Gradle modules report the kind of their build) |
|
|
313
393
|
| `elevate_scan` | Scans a module (or all modules) for updates and internal dependencies to align; lists skipped dependencies with reasons |
|
|
314
394
|
| `elevate_get_versions` | Fetches complete published version history from registry (refuses public lookups of internal packages) |
|
|
315
395
|
| `elevate_apply_updates` | Applies targeted updates with verification, major guardrails and rollback (`keepOnFailure` optional) |
|
|
@@ -321,7 +401,7 @@ Register it in your agent's MCP settings (e.g., `claude_desktop_config.json` or
|
|
|
321
401
|
|
|
322
402
|
| Key | Action |
|
|
323
403
|
| :--- | :--- |
|
|
324
|
-
| **`E`** | **Switch Ecosystem (📦 Node/npm
|
|
404
|
+
| **`E`** | **Switch Ecosystem (📦 Node/npm → ☕ Java/Maven → 🦀 Rust/Cargo → 🐘 Java/Gradle)** |
|
|
325
405
|
| **`W`** | Open module / workspace selector |
|
|
326
406
|
| **`V`** | **Pick specific version (Interactive search & filter modal)** |
|
|
327
407
|
| **`L`** | Toggle language (English ⇄ German) |
|
|
@@ -354,9 +434,9 @@ You can place an optional `elevate.config.json` file in your repository root:
|
|
|
354
434
|
* **`author`:** Optional name displayed in the top-right header.
|
|
355
435
|
* **`channel`:** `"stable"` (default, excludes betas/RCs) or `"all"` (includes pre-releases).
|
|
356
436
|
* **`locale`:** `"en"` (English), `"de"` (German), or `"auto"` (system detection).
|
|
357
|
-
* **`internalScopes`:** Internal npm scopes and Maven groupId prefixes. `@my-org` matches `@my-org/*`; `com.mycompany` matches `com.mycompany` and `com.mycompany.*` (not `com.mycompanyx`). Matching packages are looked up only in private registries. *Formerly `excludeScopes`, which is still read and reported as deprecated.*
|
|
437
|
+
* **`internalScopes`:** Internal npm scopes and Maven / Gradle groupId prefixes (for Gradle also plugin ids). `@my-org` matches `@my-org/*`; `com.mycompany` matches `com.mycompany` and `com.mycompany.*` (not `com.mycompanyx`). Matching packages are looked up only in private registries. *Formerly `excludeScopes`, which is still read and reported as deprecated.*
|
|
358
438
|
* **`mavenPlugins`:** Optional versions of the Maven plugins Elevate runs: `help` (`maven-help-plugin`, default `3.5.2`) and `versions` (`versions-maven-plugin`, default `2.22.0`). Use it when your repository manager does not offer the defaults. Invalid values fall back to the default with a warning.
|
|
359
|
-
* **`postUpdateScript`:** Optional command that replaces the default verification (`npm ls` / `mvn test-compile`). Runs in the repository root (npm)
|
|
439
|
+
* **`postUpdateScript`:** Optional command that replaces the default verification (`npm ls` / `mvn test-compile`). Runs in the repository root (npm), the module directory (Maven) or the directory of the module's Gradle build (Gradle).
|
|
360
440
|
|
|
361
441
|
---
|
|
362
442
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dennisrepa/elevate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "🪶 Elevate — Interactive Polyglot Terminal Dashboard & Agentic MCP Server for safe dependency updates across monorepos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"npm",
|
|
26
26
|
"pnpm",
|
|
27
27
|
"maven",
|
|
28
|
+
"gradle",
|
|
28
29
|
"cargo",
|
|
29
30
|
"rust",
|
|
30
31
|
"mcp",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"react": "^19.0.0",
|
|
71
72
|
"saxes": "^6.0.0",
|
|
72
73
|
"semver": "^7.6.3",
|
|
74
|
+
"smol-toml": "1.9.1",
|
|
73
75
|
"toml-eslint-parser": "^1.0.3",
|
|
74
76
|
"tsx": "^4.19.3",
|
|
75
77
|
"yaml": "^2.9.1"
|