Skip to content
Snippets Groups Projects
Unverified Commit c3bd3547 authored by James Griffiths's avatar James Griffiths Committed by GitHub
Browse files

feat(leiningen): support lein-parent (#29552)

parent 51e33dad
No related branches found
No related tags found
No related merge requests found
import { codeBlock } from 'common-tags';
import { Fixtures } from '../../../../test/fixtures'; import { Fixtures } from '../../../../test/fixtures';
import { ClojureDatasource } from '../../datasource/clojure'; import { ClojureDatasource } from '../../datasource/clojure';
import { extractFromVectors, extractVariables, trimAtKey } from './extract'; import { extractFromVectors, extractVariables, trimAtKey } from './extract';
...@@ -10,6 +11,12 @@ describe('modules/manager/leiningen/extract', () => { ...@@ -10,6 +11,12 @@ describe('modules/manager/leiningen/extract', () => {
expect(trimAtKey('foo', 'bar')).toBeNull(); expect(trimAtKey('foo', 'bar')).toBeNull();
expect(trimAtKey(':dependencies ', 'dependencies')).toBeNull(); expect(trimAtKey(':dependencies ', 'dependencies')).toBeNull();
expect(trimAtKey(':dependencies \nfoobar', 'dependencies')).toBe('foobar'); 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', () => { it('extractFromVectors', () => {
...@@ -48,6 +55,20 @@ describe('modules/manager/leiningen/extract', () => { ...@@ -48,6 +55,20 @@ describe('modules/manager/leiningen/extract', () => {
currentValue: '4.5.6', 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', () => { it('extractPackageFile', () => {
...@@ -124,6 +145,95 @@ describe('modules/manager/leiningen/extract', () => { ...@@ -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', () => { it('extractVariables', () => {
......
...@@ -26,6 +26,7 @@ export function extractFromVectors( ...@@ -26,6 +26,7 @@ export function extractFromVectors(
str: string, str: string,
ctx: ExtractContext = {}, ctx: ExtractContext = {},
vars: ExtractedVariables = {}, vars: ExtractedVariables = {},
dimensions: 1 | 2 = 2,
): PackageDependency[] { ): PackageDependency[] {
if (!str.startsWith('[')) { if (!str.startsWith('[')) {
return []; return [];
...@@ -36,7 +37,8 @@ export function extractFromVectors( ...@@ -36,7 +37,8 @@ export function extractFromVectors(
let vecPos = 0; let vecPos = 0;
let artifactId = ''; let artifactId = '';
let version = ''; 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 => const isSpace = (ch: string | null): boolean =>
!!ch && regEx(/[\s,]/).test(ch); !!ch && regEx(/[\s,]/).test(ch);
...@@ -82,7 +84,7 @@ export function extractFromVectors( ...@@ -82,7 +84,7 @@ export function extractFromVectors(
if (char === '[') { if (char === '[') {
balance += 1; balance += 1;
if (balance === 2) { if (balance === dimensions) {
vecPos = 0; vecPos = 0;
} }
} else if (char === ']') { } else if (char === ']') {
...@@ -91,15 +93,17 @@ export function extractFromVectors( ...@@ -91,15 +93,17 @@ export function extractFromVectors(
if (commentLevel === balance) { if (commentLevel === balance) {
artifactId = ''; artifactId = '';
version = ''; version = '';
commentLevel = 0; commentLevel = null;
} }
if (balance === 1) { if (balance === dimensions - 1) {
yieldDep(); yieldDep();
} else if (balance === 0) { }
if (balance === 0) {
break; break;
} }
} else if (balance === 2) { } else if (balance === dimensions) {
if (isSpace(char)) { if (isSpace(char)) {
if (!isSpace(prevChar)) { if (!isSpace(prevChar)) {
vecPos += 1; vecPos += 1;
...@@ -170,20 +174,34 @@ export function extractVariables(content: string): ExtractedVariables { ...@@ -170,20 +174,34 @@ export function extractVariables(content: string): ExtractedVariables {
return result; return result;
} }
interface CollectDepsOptions {
nested: boolean;
depType?: string;
}
function collectDeps( function collectDeps(
content: string, content: string,
key: string, key: string,
registryUrls: string[], registryUrls: string[],
vars: ExtractedVariables, vars: ExtractedVariables,
options: CollectDepsOptions = {
nested: true,
},
): PackageDependency[] { ): PackageDependency[] {
const ctx = { const ctx = {
depType: key, depType: options.depType ?? key,
registryUrls, 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 result: PackageDependency[] = [];
let restContent = trimAtKey(content, key); let restContent = trimAtKey(content, key);
while (restContent) { while (restContent) {
result = [...result, ...extractFromVectors(restContent, ctx, vars)]; result = [
...result,
...extractFromVectors(restContent, ctx, vars, dimensions),
];
restContent = trimAtKey(restContent, key); restContent = trimAtKey(restContent, key);
} }
return result; return result;
...@@ -198,6 +216,19 @@ export function extractPackageFile(content: string): PackageFileContent { ...@@ -198,6 +216,19 @@ export function extractPackageFile(content: string): PackageFileContent {
...collectDeps(content, 'managed-dependencies', registryUrls, vars), ...collectDeps(content, 'managed-dependencies', registryUrls, vars),
...collectDeps(content, 'plugins', registryUrls, vars), ...collectDeps(content, 'plugins', registryUrls, vars),
...collectDeps(content, 'pom-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 }; return { deps };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment