diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 994afc625d1f2e12f545d6c8151d736b9af67fd3..412774fd1ae5b5a0f351fb8edd11ae460b3d18a2 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -412,6 +412,7 @@ This is an advanced field, and it's recommend you seek a config review before ap Currently, this config option only works with these managers: +- `cargo` - `helmv3` - `npm` - `nuget` diff --git a/lib/modules/manager/cargo/extract.spec.ts b/lib/modules/manager/cargo/extract.spec.ts index 629f2fb61c32120ba865c6eb94a88b72cf52b21f..cf80672e7cf76cb982a66c190c94743d30013533 100644 --- a/lib/modules/manager/cargo/extract.spec.ts +++ b/lib/modules/manager/cargo/extract.spec.ts @@ -585,5 +585,19 @@ replace-with = "mcorbin" expect.not.objectContaining({ lockedVersion: expect.anything() }), ]); }); + + it('should extract project version', async () => { + const cargotoml = codeBlock` + [package] + name = "test" + version = "0.1.0" + edition = "2021" + [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 d5ec4ded972ff22689fa72f3ae9bab163202ebd4..cd0d3f746fbe4e0f23ba4b1f1d3f6fc1706f22dc 100644 --- a/lib/modules/manager/cargo/extract.ts +++ b/lib/modules/manager/cargo/extract.ts @@ -224,6 +224,7 @@ export async function extractPackageFile( } /* There are the following sections in Cargo.toml: + [package] [dependencies] [dev-dependencies] [build-dependencies] @@ -284,11 +285,18 @@ export async function extractPackageFile( if (!deps.length) { return null; } + + const packageSection = cargoManifest.package; + let version: string | undefined = undefined; + if (packageSection) { + version = packageSection.version; + } + const lockFileName = await findLocalSiblingOrParent( packageFile, 'Cargo.lock', ); - const res: PackageFileContent = { deps }; + const res: PackageFileContent = { deps, packageFileVersion: version }; if (lockFileName) { logger.debug( `Found lock file ${lockFileName} for packageFile: ${packageFile}`, diff --git a/lib/modules/manager/cargo/index.ts b/lib/modules/manager/cargo/index.ts index adbba5cfb253b91848a341cb0e16978bcecea3ba..fb62a10969670738415244a747e5a6e934eb556b 100644 --- a/lib/modules/manager/cargo/index.ts +++ b/lib/modules/manager/cargo/index.ts @@ -3,6 +3,7 @@ import { CrateDatasource } from '../../datasource/crate'; import * as cargoVersioning from '../../versioning/cargo'; import { updateArtifacts } from './artifacts'; import { extractPackageFile } from './extract'; +export { bumpPackageVersion } from './update'; export { getRangeStrategy } from './range'; export { updateLockedDependency } from './update-locked'; diff --git a/lib/modules/manager/cargo/types.ts b/lib/modules/manager/cargo/types.ts index 41208ad64e274429e859361aeca8c424f8478d8e..68bfa4740432a846df29c61dce151688c99490c5 100644 --- a/lib/modules/manager/cargo/types.ts +++ b/lib/modules/manager/cargo/types.ts @@ -1,5 +1,10 @@ import type { DEFAULT_REGISTRY_URL } from './utils'; +export interface CargoPackage { + /** Semver version */ + version: string; +} + export interface CargoDep { /** Path on disk to the crate sources */ path?: string; @@ -26,6 +31,7 @@ export interface CargoSection { export interface CargoManifest extends CargoSection { target?: Record<string, CargoSection>; workspace?: CargoSection; + package?: CargoPackage; } export interface CargoConfig { diff --git a/lib/modules/manager/cargo/update.spec.ts b/lib/modules/manager/cargo/update.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..66adeb550f7617bdfea600c6ba051a6130b2311e --- /dev/null +++ b/lib/modules/manager/cargo/update.spec.ts @@ -0,0 +1,59 @@ +import { codeBlock } from 'common-tags'; +import * as projectUpdater from '.'; + +describe('modules/manager/cargo/update', () => { + describe('bumpPackageVersion()', () => { + const content = codeBlock` + [package] + name = "test" + version = "0.0.2" + `; + + it('increments', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.2', + 'patch', + ); + const expected = content.replace('0.0.2', '0.0.3'); + expect(bumpedContent).toEqual(expected); + }); + + it('no ops', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.1', + 'patch', + ); + expect(bumpedContent).toEqual(content); + }); + + it('updates', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.1', + 'minor', + ); + const expected = content.replace('0.0.2', '0.1.0'); + expect(bumpedContent).toEqual(expected); + }); + + it('returns content if bumping errors', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '0.0.2', + true as any, + ); + expect(bumpedContent).toEqual(content); + }); + + it('does not bump version if version is not a semantic version', () => { + const { bumpedContent } = projectUpdater.bumpPackageVersion( + content, + '1', + 'patch', + ); + expect(bumpedContent).toEqual(content); + }); + }); +}); diff --git a/lib/modules/manager/cargo/update.ts b/lib/modules/manager/cargo/update.ts new file mode 100644 index 0000000000000000000000000000000000000000..196044d75f44da2387407129ce326202e488d171 --- /dev/null +++ b/lib/modules/manager/cargo/update.ts @@ -0,0 +1,55 @@ +import semver, { ReleaseType } from 'semver'; +import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; +import type { BumpPackageVersionResult } from '../types'; + +export function bumpPackageVersion( + content: string, + currentValue: string, + bumpVersion: ReleaseType, +): BumpPackageVersionResult { + logger.debug( + { bumpVersion, currentValue }, + 'Checking if we should bump Cargo.toml version', + ); + let bumpedContent = content; + + if (!semver.valid(currentValue)) { + logger.warn( + { currentValue }, + 'Unable to bump Cargo.toml version, not a valid semver', + ); + return { bumpedContent }; + } + + try { + const newCrateVersion = semver.inc(currentValue, bumpVersion); + if (!newCrateVersion) { + throw new Error('semver inc failed'); + } + + logger.debug({ newCrateVersion }); + + bumpedContent = content.replace( + regEx(`^(?<version>version[ \\t]*=[ \\t]*['"])[^'"]*`, 'm'), + `$<version>${newCrateVersion}`, + ); + + if (bumpedContent === content) { + logger.debug('Version was already bumped'); + } else { + logger.debug('Bumped Cargo.toml version'); + } + } catch (err) { + logger.warn( + { + content, + currentValue, + bumpVersion, + }, + 'Failed to bumpVersion', + ); + } + + return { bumpedContent }; +}