From 6de13229b52db122a557e842a7660edd57dcdecd Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Thu, 14 Nov 2024 10:54:13 +0100
Subject: [PATCH] feat(manager/cargo): support reading package version from
 workspace (local only) (#32533)

---
 lib/modules/manager/cargo/extract.spec.ts | 16 ++++++++++++++++
 lib/modules/manager/cargo/extract.ts      | 11 ++++++++++-
 lib/modules/manager/cargo/schema.ts       | 13 ++++++++++++-
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/lib/modules/manager/cargo/extract.spec.ts b/lib/modules/manager/cargo/extract.spec.ts
index 6b48dc8437..d379da8257 100644
--- a/lib/modules/manager/cargo/extract.spec.ts
+++ b/lib/modules/manager/cargo/extract.spec.ts
@@ -635,5 +635,21 @@ replace-with = "mcorbin"
       const res = await extractPackageFile(cargotoml, 'Cargo.toml', config);
       expect(res?.packageFileVersion).toBe('0.1.0');
     });
+
+    it('should extract project version from workspace', async () => {
+      const cargotoml = codeBlock`
+        [package]
+        name = "test"
+        version.workspace = true
+        edition = "2021"
+        [workspace.package]
+        version = "0.1.0"
+        [dependencies]
+        syn = "2.0"
+        `;
+
+      const res = await extractPackageFile(cargotoml, 'Cargo.toml', config);
+      expect(res?.packageFileVersion).toBe('0.1.0');
+    });
   });
 });
diff --git a/lib/modules/manager/cargo/extract.ts b/lib/modules/manager/cargo/extract.ts
index f71df1f222..3d090e52b7 100644
--- a/lib/modules/manager/cargo/extract.ts
+++ b/lib/modules/manager/cargo/extract.ts
@@ -1,3 +1,4 @@
+import is from '@sindresorhus/is';
 import { logger } from '../../../logger';
 import { coerceArray } from '../../../util/array';
 import { findLocalSiblingOrParent, readLocalFile } from '../../../util/fs';
@@ -248,7 +249,15 @@ export async function extractPackageFile(
   const packageSection = cargoManifest.package;
   let version: string | undefined = undefined;
   if (packageSection) {
-    version = packageSection.version;
+    if (is.string(packageSection.version)) {
+      version = packageSection.version;
+    } else if (
+      is.object(packageSection.version) &&
+      cargoManifest.workspace?.package?.version
+    ) {
+      // TODO: Support reading from parent workspace manifest?
+      version = cargoManifest.workspace.package.version;
+    }
   }
 
   const lockFileName = await findLocalSiblingOrParent(
diff --git a/lib/modules/manager/cargo/schema.ts b/lib/modules/manager/cargo/schema.ts
index 52640d4252..1a5e799e96 100644
--- a/lib/modules/manager/cargo/schema.ts
+++ b/lib/modules/manager/cargo/schema.ts
@@ -99,13 +99,24 @@ const CargoSection = z.object({
 
 const CargoWorkspace = z.object({
   dependencies: withDepType(CargoDeps, 'workspace.dependencies').optional(),
+  package: z
+    .object({
+      version: z.string().optional(),
+    })
+    .optional(),
 });
 
 const CargoTarget = z.record(z.string(), CargoSection);
 
 export const CargoManifestSchema = Toml.pipe(
   CargoSection.extend({
-    package: z.object({ version: z.string().optional() }).optional(),
+    package: z
+      .object({
+        version: z
+          .union([z.string(), z.object({ workspace: z.literal(true) })])
+          .optional(),
+      })
+      .optional(),
     workspace: CargoWorkspace.optional(),
     target: CargoTarget.optional(),
   }),
-- 
GitLab