mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 23:11:31 +00:00
feat(leiningen): support lein-parent (#29552)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { codeBlock } from 'common-tags';
|
||||
import { Fixtures } from '../../../../test/fixtures';
|
||||
import { ClojureDatasource } from '../../datasource/clojure';
|
||||
import { extractFromVectors, extractVariables, trimAtKey } from './extract';
|
||||
@@ -10,6 +11,12 @@ describe('modules/manager/leiningen/extract', () => {
|
||||
expect(trimAtKey('foo', 'bar')).toBeNull();
|
||||
expect(trimAtKey(':dependencies ', 'dependencies')).toBeNull();
|
||||
expect(trimAtKey(':dependencies \nfoobar', 'dependencies')).toBe('foobar');
|
||||
expect(
|
||||
trimAtKey(
|
||||
':parent-project {:coords [my-org/my-parent "4.3.0"]\n:inherit [:profiles]}',
|
||||
'coords',
|
||||
),
|
||||
).toBe('[my-org/my-parent "4.3.0"]\n:inherit [:profiles]}');
|
||||
});
|
||||
|
||||
it('extractFromVectors', () => {
|
||||
@@ -48,6 +55,20 @@ describe('modules/manager/leiningen/extract', () => {
|
||||
currentValue: '4.5.6',
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
extractFromVectors(
|
||||
'[my-org/my-parent "4.3.0"]\n:inherit [:profiles]}',
|
||||
{},
|
||||
{},
|
||||
1,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
datasource: ClojureDatasource.id,
|
||||
depName: 'my-org:my-parent',
|
||||
currentValue: '4.3.0',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('extractPackageFile', () => {
|
||||
@@ -124,6 +145,95 @@ describe('modules/manager/leiningen/extract', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const parentProjectSrc = codeBlock`
|
||||
(defproject org.example/parent-project "1.0.0-SNAPSHOT"
|
||||
:plugins [[lein-parent "0.3.9"]
|
||||
[lein-project-version "0.1.0"]
|
||||
[lein-shell "0.5.0"]]
|
||||
:parent-project {:coords [my-org/my-parent "4.3.0"]
|
||||
:inherit [:profiles :managed-dependencies :local-repo]}
|
||||
:profiles {:cljfmt {:plugins [[lein-cljfmt "0.9.2"]]}}
|
||||
:dependencies [[org.clojure/core.async "1.6.681"]
|
||||
[org.clojure/core.match "1.1.0"]
|
||||
[org.clojure/data.csv "1.1.0"]
|
||||
[org.clojure/tools.cli "1.1.230"]
|
||||
[metosin/malli "0.15.0"]])`;
|
||||
|
||||
expect(extractPackageFile(parentProjectSrc)).toMatchObject({
|
||||
deps: [
|
||||
{
|
||||
depName: 'org.clojure:core.async',
|
||||
datasource: 'clojure',
|
||||
depType: 'dependencies',
|
||||
registryUrls: [],
|
||||
currentValue: '1.6.681',
|
||||
},
|
||||
{
|
||||
depName: 'org.clojure:core.match',
|
||||
datasource: 'clojure',
|
||||
depType: 'dependencies',
|
||||
registryUrls: [],
|
||||
currentValue: '1.1.0',
|
||||
},
|
||||
{
|
||||
depName: 'org.clojure:data.csv',
|
||||
datasource: 'clojure',
|
||||
depType: 'dependencies',
|
||||
registryUrls: [],
|
||||
currentValue: '1.1.0',
|
||||
},
|
||||
{
|
||||
depName: 'org.clojure:tools.cli',
|
||||
datasource: 'clojure',
|
||||
depType: 'dependencies',
|
||||
registryUrls: [],
|
||||
currentValue: '1.1.230',
|
||||
},
|
||||
{
|
||||
depName: 'metosin:malli',
|
||||
datasource: 'clojure',
|
||||
depType: 'dependencies',
|
||||
registryUrls: [],
|
||||
currentValue: '0.15.0',
|
||||
},
|
||||
{
|
||||
depName: 'lein-parent:lein-parent',
|
||||
datasource: 'clojure',
|
||||
depType: 'plugins',
|
||||
registryUrls: [],
|
||||
currentValue: '0.3.9',
|
||||
},
|
||||
{
|
||||
depName: 'lein-project-version:lein-project-version',
|
||||
datasource: 'clojure',
|
||||
depType: 'plugins',
|
||||
registryUrls: [],
|
||||
currentValue: '0.1.0',
|
||||
},
|
||||
{
|
||||
depName: 'lein-shell:lein-shell',
|
||||
datasource: 'clojure',
|
||||
depType: 'plugins',
|
||||
registryUrls: [],
|
||||
currentValue: '0.5.0',
|
||||
},
|
||||
{
|
||||
depName: 'lein-cljfmt:lein-cljfmt',
|
||||
datasource: 'clojure',
|
||||
depType: 'plugins',
|
||||
registryUrls: [],
|
||||
currentValue: '0.9.2',
|
||||
},
|
||||
{
|
||||
depName: 'my-org:my-parent',
|
||||
datasource: 'clojure',
|
||||
depType: 'parent-project',
|
||||
registryUrls: [],
|
||||
currentValue: '4.3.0',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extractVariables', () => {
|
||||
|
||||
@@ -26,6 +26,7 @@ export function extractFromVectors(
|
||||
str: string,
|
||||
ctx: ExtractContext = {},
|
||||
vars: ExtractedVariables = {},
|
||||
dimensions: 1 | 2 = 2,
|
||||
): PackageDependency[] {
|
||||
if (!str.startsWith('[')) {
|
||||
return [];
|
||||
@@ -36,7 +37,8 @@ export function extractFromVectors(
|
||||
let vecPos = 0;
|
||||
let artifactId = '';
|
||||
let version = '';
|
||||
let commentLevel = 0;
|
||||
// Are we currently parsing a comment? If so, at what depth?
|
||||
let commentLevel: number | null = null;
|
||||
|
||||
const isSpace = (ch: string | null): boolean =>
|
||||
!!ch && regEx(/[\s,]/).test(ch);
|
||||
@@ -82,7 +84,7 @@ export function extractFromVectors(
|
||||
|
||||
if (char === '[') {
|
||||
balance += 1;
|
||||
if (balance === 2) {
|
||||
if (balance === dimensions) {
|
||||
vecPos = 0;
|
||||
}
|
||||
} else if (char === ']') {
|
||||
@@ -91,15 +93,17 @@ export function extractFromVectors(
|
||||
if (commentLevel === balance) {
|
||||
artifactId = '';
|
||||
version = '';
|
||||
commentLevel = 0;
|
||||
commentLevel = null;
|
||||
}
|
||||
|
||||
if (balance === 1) {
|
||||
if (balance === dimensions - 1) {
|
||||
yieldDep();
|
||||
} else if (balance === 0) {
|
||||
}
|
||||
|
||||
if (balance === 0) {
|
||||
break;
|
||||
}
|
||||
} else if (balance === 2) {
|
||||
} else if (balance === dimensions) {
|
||||
if (isSpace(char)) {
|
||||
if (!isSpace(prevChar)) {
|
||||
vecPos += 1;
|
||||
@@ -170,20 +174,34 @@ export function extractVariables(content: string): ExtractedVariables {
|
||||
return result;
|
||||
}
|
||||
|
||||
interface CollectDepsOptions {
|
||||
nested: boolean;
|
||||
depType?: string;
|
||||
}
|
||||
|
||||
function collectDeps(
|
||||
content: string,
|
||||
key: string,
|
||||
registryUrls: string[],
|
||||
vars: ExtractedVariables,
|
||||
options: CollectDepsOptions = {
|
||||
nested: true,
|
||||
},
|
||||
): PackageDependency[] {
|
||||
const ctx = {
|
||||
depType: key,
|
||||
depType: options.depType ?? key,
|
||||
registryUrls,
|
||||
};
|
||||
// A vector like [["dep-1" "1.0.0"] ["dep-2" "0.0.0"]] is nested
|
||||
// A vector like ["dep-1" "1.0.0"] is not
|
||||
const dimensions = options.nested ? 2 : 1;
|
||||
let result: PackageDependency[] = [];
|
||||
let restContent = trimAtKey(content, key);
|
||||
while (restContent) {
|
||||
result = [...result, ...extractFromVectors(restContent, ctx, vars)];
|
||||
result = [
|
||||
...result,
|
||||
...extractFromVectors(restContent, ctx, vars, dimensions),
|
||||
];
|
||||
restContent = trimAtKey(restContent, key);
|
||||
}
|
||||
return result;
|
||||
@@ -198,6 +216,19 @@ export function extractPackageFile(content: string): PackageFileContent {
|
||||
...collectDeps(content, 'managed-dependencies', registryUrls, vars),
|
||||
...collectDeps(content, 'plugins', registryUrls, vars),
|
||||
...collectDeps(content, 'pom-plugins', registryUrls, vars),
|
||||
// 'coords' is used in lein parent, and specifies zero or one
|
||||
// dependencies. These are not wrapped in a vector in the way other
|
||||
// dependencies are. The project.clj fragment looks like
|
||||
//
|
||||
// :parent-project {... :coords ["parent" "version"] ...}
|
||||
//
|
||||
// - https://github.com/achin/lein-parent
|
||||
...collectDeps(content, 'coords', registryUrls, vars, {
|
||||
nested: false,
|
||||
// The top-level key is 'parent-project', but we skip directly to 'coords'.
|
||||
// So fix the dep type label
|
||||
depType: 'parent-project',
|
||||
}),
|
||||
];
|
||||
|
||||
return { deps };
|
||||
|
||||
Reference in New Issue
Block a user