diff --git a/src/practices/Java/JavaDependenciesVersionMajorLevel.ts b/src/practices/Java/JavaDependenciesVersionMajorLevel.ts new file mode 100644 index 000000000..4b142baf4 --- /dev/null +++ b/src/practices/Java/JavaDependenciesVersionMajorLevel.ts @@ -0,0 +1,73 @@ +import { PracticeContext } from '../../contexts/practice/PracticeContext'; +import { Package } from '../../inspectors/IPackageInspector'; +import { PackageInspectorBase, SemverLevel } from '../../inspectors/package/PackageInspectorBase'; +import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; +import { DxPractice } from '../DxPracticeDecorator'; +import { IPractice } from '../IPractice'; +import * as axios from 'axios'; + +@DxPractice({ + id: 'Java.DependenciesVersionMajorLevel', + name: 'Update Dependencies of Major Level', + impact: PracticeImpact.medium, + suggestion: 'Keep the dependencies updated to have all possible features. Use, for example, Renovate Bot.', + reportOnlyOnce: true, + url: 'https://renovatebot.com/', +}) +export class JavaDependenciesVersionMajorLevel implements IPractice { + async isApplicable(ctx: PracticeContext): Promise { + return ctx.projectComponent.language === ProgrammingLanguage.Java || ctx.projectComponent.language === ProgrammingLanguage.Kotlin; + } + + async evaluate(ctx: PracticeContext): Promise { + if (ctx.fileInspector === undefined || ctx.packageInspector === undefined) { + return PracticeEvaluationResult.unknown; + } + + const pkgs = ctx.packageInspector.packages; + + if (pkgs === undefined) { + return PracticeEvaluationResult.unknown; + } + + const result = await JavaDependenciesVersionMajorLevel.searchMavenCentral(pkgs, 5); + const practiceEvaluationResult = JavaDependenciesVersionMajorLevel.isPracticing(result, SemverLevel.major, pkgs); + + return practiceEvaluationResult || PracticeEvaluationResult.practicing; + } + + static async searchMavenCentral(pkgs: Package[] | undefined, rows: number) { + const latestVersionsJson: { [key: string]: string } = {}; + const URL = 'http://search.maven.org/solrsearch/select?q='; + if (pkgs) { + for (const p of pkgs) { + const listOfIds = p.name.split(':', 2); + const listVersionsEndpoint = `${URL}${listOfIds[0]}+AND+a:${listOfIds[1]}&rows=${rows}&wt=json`; + await axios.default.get(listVersionsEndpoint).then((response) => { + latestVersionsJson[p.name] = String(response.data.response.docs.pop().latestVersion); + }); + } + } + return latestVersionsJson; + } + + static isPracticing( + result: { [key: string]: string }, + semverVersion: SemverLevel, + pkgs: Package[], + ): PracticeEvaluationResult | undefined { + for (const packageName in result) { + const parsedVersion = PackageInspectorBase.semverToPackageVersion(result[packageName]); + if (parsedVersion) { + for (const pkg of pkgs) { + if (pkg.name === packageName) { + if (parsedVersion[semverVersion] > pkg.lockfileVersion[semverVersion]) { + return PracticeEvaluationResult.notPracticing; + } + } + } + } + } + return undefined; + } +} diff --git a/src/practices/index.ts b/src/practices/index.ts index 08aa75ec8..e17a1df48 100644 --- a/src/practices/index.ts +++ b/src/practices/index.ts @@ -21,6 +21,7 @@ import { DependenciesVersionMajorLevel } from './JavaScript/DependenciesVersionM import { ESLintWithoutErrorsPractice } from './JavaScript/ESLintWithoutErrorsPractice'; import { TsGitignoreCorrectlySetPractice } from './TypeScript/TsGitignoreCorrectlySetPractice'; import { DependenciesVersionMinorPatchLevel } from './JavaScript/DependenciesVersionMinorPatchLevel'; +import { JavaDependenciesVersionMajorLevel } from './Java/JavaDependenciesVersionMajorLevel'; // register practices here export const practices = [ @@ -42,6 +43,7 @@ export const practices = [ DockerizationUsedPractice, EditorConfigIsPresentPractice, DependenciesVersionMajorLevel, + JavaDependenciesVersionMajorLevel, DependenciesVersionMinorPatchLevel, GitignoreIsPresentPractice, JsGitignoreCorrectlySetPractice,