@dennisrepa/elevate 1.5.0 → 1.6.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 +1 -1
- package/dist/cli.js +96 -23
- package/dist/cli.js.map +1 -1
- package/docs/de.md +1 -0
- package/docs/en.md +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,7 +215,7 @@ Detailed parameter references are available in [`docs/en.md`](./docs/en.md) and
|
|
|
215
215
|
* **pnpm specifics.** `catalog:` entries are updated where they are declared, in `pnpm-workspace.yaml`. A plain range on a workspace module (`^1.0.0`) is listed as *not linked* and never rewritten to `workspace:`, because pnpm resolves it from the registry. Elevate does not read pnpm settings such as `minimumReleaseAge` or the approval of build scripts, so pnpm may refuse an offered version; the update is then rolled back with pnpm's message. pnpm 8 and older, Windows and `shared-workspace-lockfile=false` are not covered.
|
|
216
216
|
* **Broken configuration stops Elevate.** An `elevate.config.json` that is not valid JSON, not an object, or whose `internalScopes` is not a list of strings is reported and Elevate exits with code `1`, because ignoring it would switch off the protection of internal packages. Without any configuration file Elevate works with defaults.
|
|
217
217
|
* **Dependency sections.** `dependencies`, `devDependencies` and `optionalDependencies` are covered. `peerDependencies` and `overrides` are never changed.
|
|
218
|
-
* **Cargo.** Requirements are raised keeping their precision, so a loose `"1"` only shows breaking updates; wildcard and compound requirements (`*`, `>=1.2, <2`), git and external path dependencies are left alone. Lock-file-only updates
|
|
218
|
+
* **Cargo.** Requirements are raised keeping their precision, so a loose `"1"` only shows breaking updates; wildcard and compound requirements (`*`, `>=1.2, <2`), git and external path dependencies are left alone. Lock-file-only updates (`[Lock]`) are offered for direct dependencies when `Cargo.lock` is behind a requirement that already allows a newer release; transitive crates are not. Registries that need authentication and `[patch]` sections are not covered; a vendored or local-registry source replacement is refused rather than bypassed.
|
|
219
219
|
* **Maven.** Maven plugin versions and declarations inside `<profiles>` are not offered. Dependencies whose version is declared outside the repository (an external parent or BOM) are listed as *not offered* with the reason.
|
|
220
220
|
|
|
221
221
|
---
|
package/dist/cli.js
CHANGED
|
@@ -1351,7 +1351,7 @@ var CargoConfigReader = class {
|
|
|
1351
1351
|
|
|
1352
1352
|
// src/version.ts
|
|
1353
1353
|
import { createRequire } from "module";
|
|
1354
|
-
var VERSION = true ? "1.
|
|
1354
|
+
var VERSION = true ? "1.6.0" : fromPackage();
|
|
1355
1355
|
|
|
1356
1356
|
// src/adapters/cargo/cargo-index.ts
|
|
1357
1357
|
var RegistryAuthRequiredError = class extends Error {
|
|
@@ -1463,6 +1463,13 @@ import semver6 from "semver";
|
|
|
1463
1463
|
// src/adapters/cargo/cargo-versions.ts
|
|
1464
1464
|
import semver5 from "semver";
|
|
1465
1465
|
var rust = (v) => semver5.coerce(v)?.version;
|
|
1466
|
+
function eligibleVersions(versions, options) {
|
|
1467
|
+
const project = options.rustVersion ? rust(options.rustVersion) : void 0;
|
|
1468
|
+
return versions.filter((v) => !v.yanked && semver5.valid(v.version)).filter((v) => options.channel === "all" || semver5.prerelease(v.version) === null).filter((v) => {
|
|
1469
|
+
const needs = v.rustVersion ? rust(v.rustVersion) : void 0;
|
|
1470
|
+
return !(project && needs && semver5.gt(needs, project));
|
|
1471
|
+
}).map((v) => v.version).sort(semver5.rcompare);
|
|
1472
|
+
}
|
|
1466
1473
|
function selectVersion(versions, options) {
|
|
1467
1474
|
const candidates = versions.filter((v) => !v.yanked && semver5.valid(v.version)).filter((v) => options.channel === "all" || semver5.prerelease(v.version) === null).sort((a, b) => semver5.rcompare(a.version, b.version));
|
|
1468
1475
|
const project = options.rustVersion ? rust(options.rustVersion) : void 0;
|
|
@@ -1549,7 +1556,7 @@ function cargoDiff(from, to) {
|
|
|
1549
1556
|
}
|
|
1550
1557
|
|
|
1551
1558
|
// src/adapters/cargo/cargo-scanner.ts
|
|
1552
|
-
import { readFileSync as
|
|
1559
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
1553
1560
|
import { join as join11, relative as relative4 } from "path";
|
|
1554
1561
|
import semver8 from "semver";
|
|
1555
1562
|
|
|
@@ -1621,6 +1628,20 @@ function locateSection(path) {
|
|
|
1621
1628
|
return { section, inWorkspace, target, rest: path.slice(i + 1) };
|
|
1622
1629
|
}
|
|
1623
1630
|
|
|
1631
|
+
// src/adapters/cargo/cargo-lockfile.ts
|
|
1632
|
+
import { existsSync as existsSync7, readFileSync as readFileSync10 } from "fs";
|
|
1633
|
+
import { getStaticTOMLValue as getStaticTOMLValue2, parseTOML as parseTOML3 } from "toml-eslint-parser";
|
|
1634
|
+
function readLockedVersions(lockFile) {
|
|
1635
|
+
const locked = /* @__PURE__ */ new Map();
|
|
1636
|
+
if (!existsSync7(lockFile)) return locked;
|
|
1637
|
+
try {
|
|
1638
|
+
const data = getStaticTOMLValue2(parseTOML3(readFileSync10(lockFile, "utf8")));
|
|
1639
|
+
for (const pkg of data.package ?? []) locked.set(pkg.name, [...locked.get(pkg.name) ?? [], pkg.version]);
|
|
1640
|
+
} catch {
|
|
1641
|
+
}
|
|
1642
|
+
return locked;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1624
1645
|
// src/adapters/cargo/cargo-scanner.ts
|
|
1625
1646
|
var CONCURRENCY2 = 6;
|
|
1626
1647
|
var DIFF_ORDER2 = { major: 0, minor: 1, patch: 2 };
|
|
@@ -1634,6 +1655,7 @@ var CargoDependencyAdapter = class {
|
|
|
1634
1655
|
const pkg = metadata.packages.find((p) => samePath(join11(p.manifest_path, ".."), module.path));
|
|
1635
1656
|
if (!pkg) return { candidates: [], skipped: [] };
|
|
1636
1657
|
const own = readDeclarations(pkg.manifest_path);
|
|
1658
|
+
const locks = readLockedVersions(join11(metadata.workspace_root, "Cargo.lock"));
|
|
1637
1659
|
const rootManifest = join11(metadata.workspace_root, "Cargo.toml");
|
|
1638
1660
|
const root = readDeclarations(rootManifest);
|
|
1639
1661
|
const groups = groupDependencies(pkg.dependencies);
|
|
@@ -1650,7 +1672,7 @@ var CargoDependencyAdapter = class {
|
|
|
1650
1672
|
return target ? alignment(primary, target, located, common) : null;
|
|
1651
1673
|
}
|
|
1652
1674
|
if (!primary.source || primary.source.startsWith("git+")) return null;
|
|
1653
|
-
const outcome = await this.registryOutcome(primary, located, pkg, metadata, common, context);
|
|
1675
|
+
const outcome = await this.registryOutcome(primary, located, pkg, metadata, locks, common, context);
|
|
1654
1676
|
const other = group.find((d) => d !== primary && !sameRequirement(d.req, primary.req));
|
|
1655
1677
|
if (outcome && "candidate" in outcome && other) {
|
|
1656
1678
|
outcome.note = {
|
|
@@ -1674,7 +1696,7 @@ var CargoDependencyAdapter = class {
|
|
|
1674
1696
|
candidates.sort((a, b) => (DIFF_ORDER2[a.diff] ?? 3) - (DIFF_ORDER2[b.diff] ?? 3));
|
|
1675
1697
|
return { candidates, skipped };
|
|
1676
1698
|
}
|
|
1677
|
-
async registryOutcome(dep, located, pkg, metadata, common, context) {
|
|
1699
|
+
async registryOutcome(dep, located, pkg, metadata, locks, common, context) {
|
|
1678
1700
|
const literal = located?.version.value ?? dep.req;
|
|
1679
1701
|
if (!isUpgradableRequirement(literal)) return null;
|
|
1680
1702
|
if (!located || !sameRequirement(located.version.value, dep.req)) {
|
|
@@ -1711,7 +1733,7 @@ var CargoDependencyAdapter = class {
|
|
|
1711
1733
|
return null;
|
|
1712
1734
|
}
|
|
1713
1735
|
const newRange = rewriteRequirement(literal, latest);
|
|
1714
|
-
if (newRange === literal) return
|
|
1736
|
+
if (newRange === literal) return lockOutcome(dep, literal, origin, versions, pkg, metadata, locks, common, context);
|
|
1715
1737
|
const tag = semver8.prerelease(latest) ? extractPreReleaseTag(latest) ?? "PRE" : void 0;
|
|
1716
1738
|
const diff = cargoDiff(floor, latest);
|
|
1717
1739
|
const candidate = {
|
|
@@ -1734,6 +1756,34 @@ var CargoDependencyAdapter = class {
|
|
|
1734
1756
|
return { candidate };
|
|
1735
1757
|
}
|
|
1736
1758
|
};
|
|
1759
|
+
function lockOutcome(dep, requirement, origin, versions, pkg, metadata, locks, common, context) {
|
|
1760
|
+
const locked = (locks.get(dep.name) ?? []).filter((v) => satisfiesRequirement(requirement, v)).sort(semver8.rcompare)[0];
|
|
1761
|
+
if (!locked) return null;
|
|
1762
|
+
const options = { channel: context.channel, rustVersion: pkg.rust_version ?? void 0 };
|
|
1763
|
+
const allowed = versions.filter((v) => satisfiesRequirement(requirement, v.version));
|
|
1764
|
+
const newer = eligibleVersions(allowed, options).filter((v) => semver8.gt(v, locked));
|
|
1765
|
+
const latest = newer[0];
|
|
1766
|
+
if (!latest) return null;
|
|
1767
|
+
const lockFile = join11(metadata.workspace_root, "Cargo.lock");
|
|
1768
|
+
return {
|
|
1769
|
+
candidate: {
|
|
1770
|
+
coordinate: { identifier: dep.name, artifact: dep.name, ecosystem: "cargo", ...dep.registry ? { registry: dep.registry } : {} },
|
|
1771
|
+
currentRange: locked,
|
|
1772
|
+
currentClean: locked,
|
|
1773
|
+
latest,
|
|
1774
|
+
newRange: latest,
|
|
1775
|
+
diff: cargoDiff(locked, latest),
|
|
1776
|
+
scope: common.scope,
|
|
1777
|
+
// A release the requirement allows is compatible by definition, so it is safe to preselect.
|
|
1778
|
+
selected: true,
|
|
1779
|
+
origin,
|
|
1780
|
+
action: "lock",
|
|
1781
|
+
declaration: { file: lockFile, kind: "lockfile", displayPath: display(context.rootDir, lockFile) },
|
|
1782
|
+
availableVersions: newer,
|
|
1783
|
+
...common.qualifier ? { qualifier: common.qualifier } : {}
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1737
1787
|
function alignment(dep, target, located, common) {
|
|
1738
1788
|
const local = target.version;
|
|
1739
1789
|
if (!located || !local || !semver8.valid(local)) return null;
|
|
@@ -1772,7 +1822,7 @@ function groupDependencies(deps) {
|
|
|
1772
1822
|
}
|
|
1773
1823
|
function readDeclarations(manifestPath) {
|
|
1774
1824
|
try {
|
|
1775
|
-
return parseCargoManifest(
|
|
1825
|
+
return parseCargoManifest(readFileSync11(manifestPath, "utf8"));
|
|
1776
1826
|
} catch {
|
|
1777
1827
|
return [];
|
|
1778
1828
|
}
|
|
@@ -1964,20 +2014,6 @@ function applyRangeEdits(source, edits) {
|
|
|
1964
2014
|
return result;
|
|
1965
2015
|
}
|
|
1966
2016
|
|
|
1967
|
-
// src/adapters/cargo/cargo-lockfile.ts
|
|
1968
|
-
import { existsSync as existsSync7, readFileSync as readFileSync11 } from "fs";
|
|
1969
|
-
import { getStaticTOMLValue as getStaticTOMLValue2, parseTOML as parseTOML3 } from "toml-eslint-parser";
|
|
1970
|
-
function readLockedVersions(lockFile) {
|
|
1971
|
-
const locked = /* @__PURE__ */ new Map();
|
|
1972
|
-
if (!existsSync7(lockFile)) return locked;
|
|
1973
|
-
try {
|
|
1974
|
-
const data = getStaticTOMLValue2(parseTOML3(readFileSync11(lockFile, "utf8")));
|
|
1975
|
-
for (const pkg of data.package ?? []) locked.set(pkg.name, [...locked.get(pkg.name) ?? [], pkg.version]);
|
|
1976
|
-
} catch {
|
|
1977
|
-
}
|
|
1978
|
-
return locked;
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
2017
|
// src/adapters/cargo/cargo-updater.ts
|
|
1982
2018
|
var UPDATE_TIMEOUT_MS = 10 * 6e4;
|
|
1983
2019
|
var workspaceDir = (module, rootDir) => module.aggregatorDir ?? module.path ?? rootDir;
|
|
@@ -1991,6 +2027,9 @@ var CargoUpdaterAdapter = class {
|
|
|
1991
2027
|
const dir = workspaceDir(module, rootDir);
|
|
1992
2028
|
const lockFile = join12(dir, "Cargo.lock");
|
|
1993
2029
|
const lockedBefore = readLockedVersions(lockFile);
|
|
2030
|
+
const lockUpdates = updates.filter((u) => u.action === "lock");
|
|
2031
|
+
updates = updates.filter((u) => u.action !== "lock");
|
|
2032
|
+
this.checkLockUpdates(lockUpdates, lockFile, lockedBefore);
|
|
1994
2033
|
const byFile = /* @__PURE__ */ new Map();
|
|
1995
2034
|
for (const update of updates) {
|
|
1996
2035
|
const file = resolve6(update.declaration?.file ?? join12(module.path, "Cargo.toml"));
|
|
@@ -2028,13 +2067,37 @@ var CargoUpdaterAdapter = class {
|
|
|
2028
2067
|
if (existsSync8(lockFile) && registryUpdates.length > 0) {
|
|
2029
2068
|
await this.refreshLock(dir, lockFile, lockedBefore, registryUpdates, onProgress);
|
|
2030
2069
|
}
|
|
2070
|
+
for (const update of lockUpdates) {
|
|
2071
|
+
const name = update.coordinate.identifier;
|
|
2072
|
+
onProgress(`Locking ${name} at ${update.latest}\u2026`);
|
|
2073
|
+
await this.cargoUpdate(dir, ["-p", `${name}@${update.currentClean}`, "--precise", update.latest]);
|
|
2074
|
+
}
|
|
2075
|
+
const parts = [];
|
|
2076
|
+
if (updates.length > 0) {
|
|
2077
|
+
parts.push(`Updated ${updates.length} requirement(s) in ${writes.length} Cargo.toml file(s)${existsSync8(lockFile) ? "; Cargo.lock refreshed" : ""}`);
|
|
2078
|
+
}
|
|
2079
|
+
if (lockUpdates.length > 0) parts.push(`locked ${lockUpdates.length} crate(s) at a newer version in Cargo.lock`);
|
|
2080
|
+
const message2 = parts.join("; ");
|
|
2031
2081
|
return {
|
|
2032
|
-
updatedCount: updates.length,
|
|
2033
|
-
auditMessage:
|
|
2082
|
+
updatedCount: updates.length + lockUpdates.length,
|
|
2083
|
+
auditMessage: `${message2.charAt(0).toUpperCase()}${message2.slice(1)}.`,
|
|
2034
2084
|
auditSeverity: "clean",
|
|
2035
2085
|
integrityViolations: []
|
|
2036
2086
|
};
|
|
2037
2087
|
}
|
|
2088
|
+
/** A lock-only update needs a lock file that still holds the version the scan saw. */
|
|
2089
|
+
checkLockUpdates(lockUpdates, lockFile, locked) {
|
|
2090
|
+
if (lockUpdates.length === 0) return;
|
|
2091
|
+
if (!existsSync8(lockFile)) {
|
|
2092
|
+
throw new InstallError(`${lockFile} does not exist any more; rescan the module.`);
|
|
2093
|
+
}
|
|
2094
|
+
for (const update of lockUpdates) {
|
|
2095
|
+
const name = update.coordinate.identifier;
|
|
2096
|
+
if (!(locked.get(name) ?? []).includes(update.currentClean)) {
|
|
2097
|
+
throw new InstallError(`Cargo.lock no longer locks ${name} at ${update.currentClean}; rescan the module.`);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2038
2101
|
async resync() {
|
|
2039
2102
|
}
|
|
2040
2103
|
async refreshLock(dir, lockFile, before, updates, onProgress) {
|
|
@@ -2075,11 +2138,13 @@ var same = (a, b) => relative5(resolve7(a), resolve7(b)) === "";
|
|
|
2075
2138
|
function planCheck(metadata, module, changedFiles, locked) {
|
|
2076
2139
|
const args = ["check", "--all-targets", ...locked ? ["--locked"] : []];
|
|
2077
2140
|
const rootManifest = join13(metadata.workspace_root, "Cargo.toml");
|
|
2141
|
+
const lockFile = join13(metadata.workspace_root, "Cargo.lock");
|
|
2078
2142
|
const memberManifests = new Set(metadata.packages.map((p) => resolve7(p.manifest_path)));
|
|
2079
2143
|
if (changedFiles.some((f) => same(f, rootManifest))) {
|
|
2080
2144
|
const isVirtualRoot = !memberManifests.has(resolve7(rootManifest));
|
|
2081
2145
|
if (isVirtualRoot || metadata.packages.length > 1) return [...args, "--workspace"];
|
|
2082
2146
|
}
|
|
2147
|
+
if (changedFiles.length > 0 && changedFiles.every((f) => same(f, lockFile))) return [...args, "--workspace"];
|
|
2083
2148
|
const changed = new Set(
|
|
2084
2149
|
metadata.packages.filter((p) => changedFiles.some((f) => same(f, p.manifest_path))).map((p) => p.name)
|
|
2085
2150
|
);
|
|
@@ -3480,6 +3545,7 @@ var de = {
|
|
|
3480
3545
|
prod: "(prod/compile)",
|
|
3481
3546
|
align: "[Angleichen]",
|
|
3482
3547
|
internal: "[Intern]",
|
|
3548
|
+
lock: "[Lock]",
|
|
3483
3549
|
shared: (count) => `[+${count} Crates]`
|
|
3484
3550
|
},
|
|
3485
3551
|
status: {
|
|
@@ -3591,6 +3657,7 @@ var en = {
|
|
|
3591
3657
|
prod: "(prod/compile)",
|
|
3592
3658
|
align: "[Align]",
|
|
3593
3659
|
internal: "[Internal]",
|
|
3660
|
+
lock: "[Lock]",
|
|
3594
3661
|
shared: (count) => `[+${count} crates]`
|
|
3595
3662
|
},
|
|
3596
3663
|
status: {
|
|
@@ -4361,6 +4428,10 @@ var PackageRow = ({ item, isFocused, t }) => {
|
|
|
4361
4428
|
t.badges.align,
|
|
4362
4429
|
" "
|
|
4363
4430
|
] }),
|
|
4431
|
+
item.action === "lock" && /* @__PURE__ */ jsxs5(Text5, { bold: true, color: theme.colors.brandLight, children: [
|
|
4432
|
+
t.badges.lock,
|
|
4433
|
+
" "
|
|
4434
|
+
] }),
|
|
4364
4435
|
item.origin.kind === "private" && /* @__PURE__ */ jsxs5(Text5, { color: theme.colors.brandLight, children: [
|
|
4365
4436
|
t.badges.internal,
|
|
4366
4437
|
" "
|
|
@@ -5397,7 +5468,7 @@ async function handleScanCommand(options, config) {
|
|
|
5397
5468
|
if (result.candidates.length === 0) console.log(" \u2728 All dependencies are up to date.");
|
|
5398
5469
|
for (const u of result.candidates) {
|
|
5399
5470
|
const diffTag = `[${u.diff.toUpperCase()}]`.padEnd(9);
|
|
5400
|
-
const actionTag = u.action === "align" ? "[ALIGN] " : u.origin.kind === "private" ? "[INTERNAL] " : "";
|
|
5471
|
+
const actionTag = u.action === "align" ? "[ALIGN] " : u.action === "lock" ? "[LOCK] " : u.origin.kind === "private" ? "[INTERNAL] " : "";
|
|
5401
5472
|
const preBadge = u.isPreRelease ? `[${u.preReleaseTag || "PRE"}] ` : "";
|
|
5402
5473
|
const where = u.declaration && u.declaration.displayPath !== modulePom ? ` (in ${u.declaration.displayPath}${u.declaration.propertyName ? ` \${${u.declaration.propertyName}}` : ""})` : "";
|
|
5403
5474
|
console.log(
|
|
@@ -5534,6 +5605,8 @@ function retarget(found, target, options) {
|
|
|
5534
5605
|
const isPreRelease = isPreReleaseVersion(target);
|
|
5535
5606
|
return {
|
|
5536
5607
|
...found,
|
|
5608
|
+
// A lock update pins exactly the version that was picked.
|
|
5609
|
+
...found.action === "lock" ? { latest: target } : {},
|
|
5537
5610
|
newRange: policyOf(options).rewrite(found.currentRange, target),
|
|
5538
5611
|
diff,
|
|
5539
5612
|
selected: true,
|