diff --git a/build.gradle b/build.gradle index 29b9c2ea..caf31db2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,5 @@ buildscript { repositories { - jcenter() mavenCentral() maven { url "https://repo.maven.apache.org/maven2" } } @@ -21,6 +20,7 @@ plugins { id 'com.github.kt3k.coveralls' version '2.10.2' id 'pl.allegro.tech.build.axion-release' version '1.12.1' id 'com.github.johnrengelman.shadow' version '6.1.0' + id 'org.jetbrains.kotlin.jvm' version '1.7.0' } scmVersion { @@ -61,7 +61,6 @@ run { repositories { mavenCentral() maven { url "https://central.maven.org/maven2" } - jcenter() } //noinspection GroovyAssignabilityCheck @@ -132,16 +131,14 @@ dependencies { // external processes implementation 'org.zeroturnaround:zt-exec:1.8' - implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.4.10' - // ktlint https://github.com/shyiko/ktlint - implementation 'com.pinterest.ktlint:ktlint-core:0.39.0' - implementation 'com.pinterest.ktlint:ktlint-ruleset-standard:0.39.0' + implementation 'com.pinterest.ktlint:ktlint-core:0.45.2' + implementation 'com.pinterest.ktlint:ktlint-ruleset-standard:0.45.2' // detekt - implementation 'io.gitlab.arturbosch.detekt:detekt-tooling:1.14.0' - runtimeOnly 'io.gitlab.arturbosch.detekt:detekt-core:1.14.0' - runtimeOnly 'io.gitlab.arturbosch.detekt:detekt-rules:1.14.0' + implementation 'io.gitlab.arturbosch.detekt:detekt-tooling:1.20.0' + runtimeOnly 'io.gitlab.arturbosch.detekt:detekt-core:1.20.0' + runtimeOnly 'io.gitlab.arturbosch.detekt:detekt-rules:1.20.0' // transitive dependency that used non-SSL version of Maven Central // and version 1.74 that was not found diff --git a/src/main/java/pl/touk/sputnik/processor/ktlint/KtLintProcessorFactory.java b/src/main/java/pl/touk/sputnik/processor/ktlint/KtLintProcessorFactory.java index c6859078..760665be 100644 --- a/src/main/java/pl/touk/sputnik/processor/ktlint/KtLintProcessorFactory.java +++ b/src/main/java/pl/touk/sputnik/processor/ktlint/KtLintProcessorFactory.java @@ -7,7 +7,7 @@ public class KtLintProcessorFactory implements ReviewProcessorFactory { @Override public boolean isEnabled(Configuration configuration) { - return Boolean.valueOf(configuration.getProperty(GeneralOption.KTLINT_ENABLED)); + return Boolean.parseBoolean(configuration.getProperty(GeneralOption.KTLINT_ENABLED)); } @Override diff --git a/src/main/java/pl/touk/sputnik/processor/ktlint/KtlintProcessor.java b/src/main/java/pl/touk/sputnik/processor/ktlint/KtlintProcessor.java index 216f6129..96feb19b 100644 --- a/src/main/java/pl/touk/sputnik/processor/ktlint/KtlintProcessor.java +++ b/src/main/java/pl/touk/sputnik/processor/ktlint/KtlintProcessor.java @@ -3,6 +3,7 @@ import com.pinterest.ktlint.core.KtLint; import com.pinterest.ktlint.core.RuleSet; import com.pinterest.ktlint.core.RuleSetProvider; +import com.pinterest.ktlint.core.api.EditorConfigOverride; import org.apache.commons.io.IOUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,6 +18,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -62,7 +65,7 @@ private ReviewResult processFiles(List filePaths) { ReviewResult result = new ReviewResult(); for (String filePath : filePaths) { String text = readFile(filePath); - KtLint.INSTANCE.lint(new KtLint.Params( + KtLint.INSTANCE.lint(new KtLint.ExperimentalParams( null, text, ruleSets, @@ -70,14 +73,18 @@ private ReviewResult processFiles(List filePaths) { new LintErrorConverter(result, filePath, excludedRules), false, null, - false)); + false, + EditorConfigOverride.Companion.getEmptyEditorConfigOverride(), + false + ) + ); } return result; } private String readFile(String filePath) { try { - return IOUtils.toString(new FileInputStream(new File(filePath))); + return IOUtils.toString(Files.newInputStream(Paths.get(filePath))); } catch (IOException e) { throw new RuntimeException("Cannot read file " + filePath, e); } diff --git a/src/test/java/pl/touk/sputnik/processor/detekt/DetektProcessorTest.java b/src/test/java/pl/touk/sputnik/processor/detekt/DetektProcessorTest.java index 948873f6..bda5d3c9 100644 --- a/src/test/java/pl/touk/sputnik/processor/detekt/DetektProcessorTest.java +++ b/src/test/java/pl/touk/sputnik/processor/detekt/DetektProcessorTest.java @@ -30,7 +30,7 @@ class DetektProcessorTest { private Configuration config; @BeforeEach - void setUp() throws Exception { + void setUp() { config = ConfigurationBuilder.initFromResource(CONFIGURATION_WITH_KTLINT_ENABLED_AND_WITH_DETEKT_CONFIG_FILE); sut = new DetektProcessor(config); } @@ -44,7 +44,7 @@ void shouldReturnViolationsOnlyForOneRequestedFile() { assertThat(result).isNotNull(); assertThat(result.getViolations()) .hasSize(3) - .contains(new Violation(VIOLATIONS_1, 1, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)) + .contains(new Violation(VIOLATIONS_1, 14, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)) .contains(new Violation(VIOLATIONS_1, 3, "[style/WildcardImport] Wildcard imports should be replaced with imports using fully qualified class names. Wildcard imports can lead to naming conflicts. A library update can introduce naming clashes with your classes which results in compilation errors.", Severity.INFO)) .contains(new Violation(VIOLATIONS_1, 7, "[style/MagicNumber] Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers.", Severity.INFO)); } @@ -59,8 +59,8 @@ void shouldReturnViolationsOnlyForRequestedFiles() { assertThat(result.getViolations()) .hasSize(3) .contains(new Violation(VIOLATIONS_3, 3, "[empty-blocks/EmptyClassBlock] Empty block of code detected. As they serve no purpose they should be removed.", Severity.INFO)) - .contains(new Violation(VIOLATIONS_2, 1, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)) - .contains(new Violation(VIOLATIONS_3, 1, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)); + .contains(new Violation(VIOLATIONS_2, 3, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)) + .contains(new Violation(VIOLATIONS_3, 4, "[style/NewLineAtEndOfFile] Checks whether files end with a line separator.", Severity.INFO)); } @Test @@ -72,7 +72,7 @@ void shouldReturnGlobalScopeViolation() { assertThat(result).isNotNull(); assertThat(result.getViolations()) .hasSize(1) - .contains(new Violation(VIOLATIONS_4, 7, "[coroutines/GlobalCoroutineUsage] Usage of GlobalScope instance is highly discouraged", Severity.ERROR)); + .contains(new Violation(VIOLATIONS_4, 7, "[coroutines/GlobalCoroutineUsage] The usage of the `GlobalScope` instance is highly discouraged.", Severity.ERROR)); } @Test diff --git a/src/test/resources/detekt/config/config.yml b/src/test/resources/detekt/config/config.yml index 5516dcec..51b0d906 100644 --- a/src/test/resources/detekt/config/config.yml +++ b/src/test/resources/detekt/config/config.yml @@ -17,11 +17,18 @@ processors: active: true exclude: # - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' # - 'FunctionCountProcessor' # - 'PropertyCountProcessor' - # - 'ClassCountProcessor' - # - 'PackageCountProcessor' - # - 'KtFileCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' console-reports: active: true @@ -31,6 +38,7 @@ console-reports: # - 'NotificationReport' # - 'FindingsReport' # - 'FileBasedFindingsReport' + # - 'LiteFindingsReport' output-reports: active: true @@ -49,9 +57,16 @@ comments: active: false CommentOverPrivateProperty: active: false + DeprecatedBlockTag: + active: false EndOfSentenceFormat: active: false endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + OutdatedDocumentation: + active: false + matchTypeParameters: true + matchDeclarationsOrder: true + allowParamOnConstructorProperties: false UndocumentedPublicClass: active: false searchInNestedClass: true @@ -79,7 +94,16 @@ complexity: ignoreSingleWhenExpression: false ignoreSimpleWhenEntries: false ignoreNestingFunctions: false - nestingFunctions: [run, let, apply, with, also, use, forEach, isNotNull, ifNull] + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' LabeledExpression: active: false ignoredLabels: [] @@ -95,10 +119,14 @@ complexity: constructorThreshold: 7 ignoreDefaultParameters: false ignoreDataClasses: true - ignoreAnnotated: [] + ignoreAnnotatedParameter: [] MethodOverloading: active: false threshold: 6 + NamedArguments: + active: false + threshold: 3 + ignoreArgumentsMatchingNames: false NestedBlockDepth: active: true threshold: 4 @@ -127,8 +155,18 @@ coroutines: active: true GlobalCoroutineUsage: active: true + InjectDispatcher: + active: false + dispatcherNames: + - 'IO' + - 'Default' + - 'Unconfined' RedundantSuspendModifier: active: false + SleepInsteadOfDelay: + active: false + SuspendFunWithCoroutineScopeReceiver: + active: false SuspendFunWithFlowReturnType: active: false @@ -171,14 +209,20 @@ exceptions: active: true ExceptionRaisedInUnexpectedLocation: active: false - methodNames: [toString, hashCode, equals, finalize] + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' InstanceOfCheckForException: active: false excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] NotImplementedDeclaration: active: false - PrintStackTrace: + ObjectExtendsThrowable: active: false + PrintStackTrace: + active: true RethrowCaughtException: active: false ReturnFromFinally: @@ -187,10 +231,10 @@ exceptions: SwallowedException: active: false ignoredExceptionTypes: - - InterruptedException - - NumberFormatException - - ParseException - - MalformedURLException + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' allowedExceptionNameRegex: '_|(ignore|expected).*' ThrowingExceptionFromFinally: active: false @@ -200,159 +244,44 @@ exceptions: active: false excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] exceptions: - - IllegalArgumentException - - IllegalStateException - - IOException + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' ThrowingNewInstanceOfSameException: active: false TooGenericExceptionCaught: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] exceptionNames: - - ArrayIndexOutOfBoundsException - - Error - - Exception - - IllegalMonitorStateException - - NullPointerException - - IndexOutOfBoundsException - - RuntimeException - - Throwable + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' allowedExceptionNameRegex: '_|(ignore|expected).*' TooGenericExceptionThrown: active: true exceptionNames: - - Error - - Exception - - Throwable - - RuntimeException - -formatting: - active: true - android: false - autoCorrect: true - AnnotationOnSeparateLine: - active: false - autoCorrect: true - AnnotationSpacing: - active: false - autoCorrect: true - ArgumentListWrapping: - active: false - autoCorrect: true - ChainWrapping: - active: true - autoCorrect: true - CommentSpacing: - active: true - autoCorrect: true - EnumEntryNameCase: - active: false - autoCorrect: true - Filename: - active: true - FinalNewline: - active: true - autoCorrect: true - insertFinalNewLine: true - ImportOrdering: - active: false - autoCorrect: true - layout: 'idea' - Indentation: - active: false - autoCorrect: true - indentSize: 4 - continuationIndentSize: 4 - MaximumLineLength: - active: true - maxLineLength: 120 - ModifierOrdering: - active: true - autoCorrect: true - MultiLineIfElse: - active: true - autoCorrect: true - NoBlankLineBeforeRbrace: - active: true - autoCorrect: true - NoConsecutiveBlankLines: - active: true - autoCorrect: true - NoEmptyClassBody: - active: true - autoCorrect: true - NoEmptyFirstLineInMethodBlock: - active: false - autoCorrect: true - NoLineBreakAfterElse: - active: true - autoCorrect: true - NoLineBreakBeforeAssignment: - active: true - autoCorrect: true - NoMultipleSpaces: - active: true - autoCorrect: true - NoSemicolons: - active: true - autoCorrect: true - NoTrailingSpaces: - active: true - autoCorrect: true - NoUnitReturn: - active: true - autoCorrect: true - NoUnusedImports: - active: true - autoCorrect: true - NoWildcardImports: - active: true - PackageName: - active: true - autoCorrect: true - ParameterListWrapping: - active: true - autoCorrect: true - indentSize: 4 - SpacingAroundColon: - active: true - autoCorrect: true - SpacingAroundComma: - active: true - autoCorrect: true - SpacingAroundCurly: - active: true - autoCorrect: true - SpacingAroundDot: - active: true - autoCorrect: true - SpacingAroundDoubleColon: - active: false - autoCorrect: true - SpacingAroundKeyword: - active: true - autoCorrect: true - SpacingAroundOperators: - active: true - autoCorrect: true - SpacingAroundParens: - active: true - autoCorrect: true - SpacingAroundRangeOperator: - active: true - autoCorrect: true - SpacingBetweenDeclarationsWithAnnotations: - active: false - autoCorrect: true - SpacingBetweenDeclarationsWithComments: - active: false - autoCorrect: true - StringTemplate: - active: true - autoCorrect: true + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' naming: active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are)' + ignoreOverridden: true ClassNaming: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] @@ -383,10 +312,9 @@ naming: FunctionNaming: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] - functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)' + functionPattern: '[a-z][a-zA-Z0-9]*' excludeClassPattern: '$^' ignoreOverridden: true - ignoreAnnotated: ['Composable'] FunctionParameterNaming: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] @@ -396,12 +324,18 @@ naming: InvalidPackageDeclaration: active: false rootPackage: '' + requireRootInDeclaration: false + LambdaParameterNaming: + active: false + parameterPattern: '[a-z][A-Za-z0-9]*|_' MatchingDeclarationName: active: true mustBeFirst: true MemberNameEqualsClassName: active: true ignoreOverridden: true + NoNameShadowing: + active: false NonBooleanPropertyPrefixedWithIs: active: false excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] @@ -452,14 +386,37 @@ performance: potential-bugs: active: true + AvoidReferentialEquality: + active: false + forbiddenTypePatterns: + - 'kotlin.String' + CastToNullableType: + active: false Deprecation: active: false + DontDowncastCollectionTypes: + active: false + DoubleMutabilityForCollection: + active: false + mutableTypes: + - 'kotlin.collections.MutableList' + - 'kotlin.collections.MutableMap' + - 'kotlin.collections.MutableSet' + - 'java.util.ArrayList' + - 'java.util.LinkedHashSet' + - 'java.util.HashSet' + - 'java.util.LinkedHashMap' + - 'java.util.HashMap' DuplicateCaseInWhenExpression: active: true + ElseCaseInsteadOfExhaustiveWhen: + active: false EqualsAlwaysReturnsTrueOrFalse: active: true EqualsWithHashCodeExist: active: true + ExitOutsideMain: + active: false ExplicitGarbageCollectionCall: active: true HasPlatformType: @@ -467,7 +424,12 @@ potential-bugs: IgnoredReturnValue: active: false restrictToAnnotatedMethods: true - returnValueAnnotations: ['*.CheckReturnValue', '*.CheckResult'] + returnValueAnnotations: + - '*.CheckResult' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - '*.CanIgnoreReturnValue' + ignoreFunctionCall: [] ImplicitDefaultLocale: active: false ImplicitUnitReturnType: @@ -486,8 +448,14 @@ potential-bugs: ignoreOnClassesPattern: '' MapGetWithNotNullAssertionOperator: active: false + MissingPackageDeclaration: + active: false + excludes: ['**/*.kts'] MissingWhenCase: active: true + allowElseExpression: true + NullCheckOnMutableProperty: + active: false NullableToStringCall: active: false RedundantElseInWhen: @@ -497,12 +465,17 @@ potential-bugs: UnnecessaryNotNullOperator: active: false UnnecessarySafeCall: + active: true + UnreachableCatchBlock: active: false UnreachableCode: active: true UnsafeCallOnNullableType: active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] UnsafeCast: + active: true + UnusedUnaryOperator: active: false UselessPostfixExpression: active: false @@ -511,6 +484,8 @@ potential-bugs: style: active: true + CanBeNonNullable: + active: false ClassOrdering: active: false CollapsibleIfStatements: @@ -520,6 +495,9 @@ style: conversionFunctionPrefix: 'to' DataClassShouldBeImmutable: active: false + DestructuringDeclarationWithTooManyEntries: + active: false + maxDestructuringEntries: 3 EqualsNullCall: active: true EqualsOnSignatureLine: @@ -533,18 +511,27 @@ style: includeLineWrapping: false ForbiddenComment: active: true - values: ['TODO:', 'FIXME:', 'STOPSHIP:'] + values: + - 'FIXME:' + - 'STOPSHIP:' + - 'TODO:' allowedPatterns: '' + customMessage: '' ForbiddenImport: active: false imports: [] forbiddenPatterns: '' ForbiddenMethodCall: active: false - methods: ['kotlin.io.println', 'kotlin.io.print'] + methods: + - 'kotlin.io.print' + - 'kotlin.io.println' ForbiddenPublicDataClass: active: false - ignorePackages: ['*.internal', '*.internal.*'] + excludes: ['**'] + ignorePackages: + - '*.internal' + - '*.internal.*' ForbiddenVoid: active: false ignoreOverridden: false @@ -552,12 +539,14 @@ style: FunctionOnlyReturningConstant: active: true ignoreOverridableFunction: true - excludedFunctions: 'describeContents' - excludeAnnotatedFunction: ['dagger.Provides'] + ignoreActualFunction: true + excludedFunctions: '' LibraryCodeMustSpecifyReturnType: active: true + excludes: ['**'] LibraryEntitiesShouldNotBePublic: active: false + excludes: ['**'] LoopWithTooManyJumpStatements: active: true maxJumpCount: 1 @@ -574,6 +563,7 @@ style: ignoreNamedArgument: true ignoreEnums: false ignoreRanges: false + ignoreExtensionFunctions: true MandatoryBracesIfStatements: active: false MandatoryBracesLoops: @@ -588,12 +578,16 @@ style: active: true ModifierOrder: active: true + MultilineLambdaItParameter: + active: false NestedClassesVisibility: active: false NewLineAtEndOfFile: active: true NoTabs: active: false + ObjectLiteralToLambda: + active: false OptionalAbstractKeyword: active: true OptionalUnit: @@ -606,6 +600,8 @@ style: active: true RedundantExplicitType: active: false + RedundantHigherOrderMapUsage: + active: false RedundantVisibilityModifierRule: active: false ReturnCount: @@ -624,20 +620,26 @@ style: ThrowsCount: active: true max: 2 + excludeGuardClauses: false TrailingWhitespace: active: false UnderscoresInNumericLiterals: active: false - acceptableDecimalLength: 5 + acceptableLength: 4 + allowNonStandardGrouping: false UnnecessaryAbstractClass: active: true excludeAnnotatedClasses: ['dagger.Module'] UnnecessaryAnnotationUseSiteTarget: active: false UnnecessaryApply: + active: true + UnnecessaryFilter: active: false UnnecessaryInheritance: active: true + UnnecessaryInnerClass: + active: false UnnecessaryLet: active: false UnnecessaryParentheses: @@ -651,6 +653,8 @@ style: UnusedPrivateMember: active: false allowedNames: '(_|ignored|expected|serialVersionUID)' + UseAnyOrNoneInsteadOfFind: + active: false UseArrayLiteralsInAnnotations: active: false UseCheckNotNull: @@ -659,12 +663,17 @@ style: active: false UseDataClass: active: false - excludeAnnotatedClasses: [] allowVars: false UseEmptyCounterpart: active: false + UseIfEmptyOrIfBlank: + active: false UseIfInsteadOfWhen: active: false + UseIsNullOrEmpty: + active: false + UseOrEmpty: + active: false UseRequire: active: false UseRequireNotNull: