diff --git a/.github/workflows/android-ci.yaml b/.github/workflows/android-ci.yaml new file mode 100644 index 00000000..97986dfe --- /dev/null +++ b/.github/workflows/android-ci.yaml @@ -0,0 +1,25 @@ +name: Android CI +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build + + - name: Run ktlint, detekt + run: ./gradlew ktlintCheck detekt diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 87519aed..35d30968 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -6,6 +6,8 @@ plugins { dependencies { implementation(libs.android.gradlePlugin) implementation(libs.kotlin.gradlePlugin) + implementation(libs.detekt.plugin) + implementation(libs.ktlint.plugin) compileOnly(libs.compose.compiler.gradle.plugin) } diff --git a/build-logic/src/main/kotlin/co/kr/tnt/KotlinAndroid.kt b/build-logic/src/main/kotlin/co/kr/tnt/KotlinAndroid.kt index ccff36f5..a145cd9e 100644 --- a/build-logic/src/main/kotlin/co/kr/tnt/KotlinAndroid.kt +++ b/build-logic/src/main/kotlin/co/kr/tnt/KotlinAndroid.kt @@ -2,6 +2,7 @@ package co.kr.tnt import org.gradle.api.JavaVersion import org.gradle.api.Project +import org.gradle.api.tasks.compile.JavaCompile import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.withType @@ -53,4 +54,9 @@ internal fun Project.configureKotlin() { ) } } + + tasks.withType().configureEach { + sourceCompatibility = "17" + targetCompatibility = "17" + } } diff --git a/build-logic/src/main/kotlin/co/kr/tnt/KotlinLint.kt b/build-logic/src/main/kotlin/co/kr/tnt/KotlinLint.kt new file mode 100644 index 00000000..a915513e --- /dev/null +++ b/build-logic/src/main/kotlin/co/kr/tnt/KotlinLint.kt @@ -0,0 +1,42 @@ +package co.kr.tnt + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.jlleitschuh.gradle.ktlint.KtlintExtension + +internal fun Project.configureKtLint() { + extensions.configure { + android.set(true) + verbose.set(true) + outputToConsole.set(true) + additionalEditorconfig.set( + mapOf( + "ktlint_standard_no-wildcard-imports" to "disabled", + "ktlint_standard_filename" to "disabled", + "ktlint_standard_function-naming" to "disabled", + "ktlint_standard_function-signature" to "disabled", + "ktlint_standard_class-naming" to "disabled", + "ktlint_standard_annotation" to "disabled", + "ktlint_standard_blank-line-before-declaration" to "disabled", + "ktlint_standard_string-template-indent" to "disabled", + "ktlint_standard_multiline-expression-wrapping" to "disabled", + "max_line_length" to "120" + ) + ) + reporters { + reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.PLAIN) + } + } +} + +internal fun Project.configureDetekt() { + with(pluginManager) { + apply("io.gitlab.arturbosch.detekt") + } + + val libs = extensions.libs + dependencies { + "detektPlugins"(libs.findLibrary("detekt.formatting").get()) + } +} diff --git a/build-logic/src/main/kotlin/tnt.android.library.gradle.kts b/build-logic/src/main/kotlin/tnt.android.library.gradle.kts index ed99088b..2c51a728 100644 --- a/build-logic/src/main/kotlin/tnt.android.library.gradle.kts +++ b/build-logic/src/main/kotlin/tnt.android.library.gradle.kts @@ -5,6 +5,7 @@ import co.kr.tnt.configureTest plugins { id("com.android.library") + id("tnt.verify.lint") } configureKotlinAndroid() diff --git a/build-logic/src/main/kotlin/tnt.kotlin.library.gradle.kts b/build-logic/src/main/kotlin/tnt.kotlin.library.gradle.kts index e88db2a1..d0eb0701 100644 --- a/build-logic/src/main/kotlin/tnt.kotlin.library.gradle.kts +++ b/build-logic/src/main/kotlin/tnt.kotlin.library.gradle.kts @@ -3,6 +3,7 @@ import co.kr.tnt.configureTest plugins { kotlin("jvm") + id("tnt.verify.lint") } configureKotlin() diff --git a/build-logic/src/main/kotlin/tnt.verify.lint.gradle.kts b/build-logic/src/main/kotlin/tnt.verify.lint.gradle.kts new file mode 100644 index 00000000..f57621ea --- /dev/null +++ b/build-logic/src/main/kotlin/tnt.verify.lint.gradle.kts @@ -0,0 +1,27 @@ +import co.kr.tnt.configureDetekt +import co.kr.tnt.configureKtLint + +plugins { + id("org.jlleitschuh.gradle.ktlint") +} + +configureKtLint() +configureDetekt() + +tasks.withType().configureEach { + // Target version of the generated JVM bytecode. It is used for type resolution. + jvmTarget = JavaVersion.VERSION_17.majorVersion + + buildUponDefaultConfig = true // preconfigure defaults + allRules = false // activate all available (even unstable) rules. + parallel = true + config.setFrom(listOf(file("$rootDir/config/detekt/detekt.yml"))) // point to your custom config defining rules to run, overwriting default behavior + + reports { + file("$rootDir/build/reports/test/${project.name}/").mkdirs() + html.required.set(true) // observe findings in your browser with structure and code snippets + html.outputLocation.set(file("$rootDir/build/reports/detekt/${project.name}.html")) + xml.required.set(true) // checkstyle like format mainly for integrations like Jenkins + xml.outputLocation.set(file("$rootDir/build/reports/detekt/${project.name}.xml")) + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 448602f4..2e27857d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,4 +15,6 @@ plugins { alias(libs.plugins.hilt) apply false alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.ksp) apply false + alias(libs.plugins.detekt) apply false + alias(libs.plugins.ktlint) } diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 00000000..020e380f --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,802 @@ +#build: +# maxIssues: 0 +# excludeCorrectable: false +# weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +#config: +# validation: true +# warningsAsErrors: false + # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' +# excludes: '' + +#processors: +# active: true +# exclude: +# - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' + +console-reports: + active: true +# exclude: +# - 'ProjectStatisticsReport' +# - 'ComplexityReport' +# - 'NotificationReport' + # - 'FindingsReport' +# - 'FileBasedFindingsReport' +# - 'LiteFindingsReport' + +#output-reports: +# active: true +# exclude: + # - 'TxtOutputReport' + # - 'XmlOutputReport' + # - 'HtmlOutputReport' + +comments: + active: true +# AbsentOrWrongFileLicense: +# active: false +# licenseTemplateFile: 'license.template' +# licenseTemplateIsRegex: false +# CommentOverPrivateFunction: +# active: false +# CommentOverPrivateProperty: +# active: false +# DeprecatedBlockTag: +# active: false +# EndOfSentenceFormat: +# active: false +# endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' +# UndocumentedPublicClass: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# searchInNestedClass: true +# searchInInnerClass: true +# searchInInnerObject: true +# searchInInnerInterface: true +# UndocumentedPublicFunction: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# UndocumentedPublicProperty: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + +complexity: + active: true + ComplexCondition: + active: true + threshold: 5 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + CyclomaticComplexMethod: + active: true + threshold: 50 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [] + LargeClass: + active: true + threshold: 1000 + LongMethod: + active: true + threshold: 400 + LongParameterList: + active: false +# functionThreshold: 6 +# constructorThreshold: 7 +# ignoreDefaultParameters: false +# ignoreDataClasses: true +# ignoreAnnotatedParameter: [] + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + MethodOverloading: + active: false + threshold: 6 + NamedArguments: + active: false + threshold: 3 + NestedBlockDepth: + active: true + threshold: 10 + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + thresholdInFiles: 100 + thresholdInClasses: 100 + thresholdInInterfaces: 100 + thresholdInObjects: 100 + thresholdInEnums: 100 + ignoreDeprecated: false + ignorePrivate: false + ignoreOverridden: false + +coroutines: + active: true + GlobalCoroutineUsage: + active: false + RedundantSuspendModifier: + active: false + SleepInsteadOfDelay: + active: false + SuspendFunWithFlowReturnType: + active: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: '_|(ignore|expected).*' + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverridden: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyTryBlock: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: true + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' + InstanceOfCheckForException: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: false + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + - 'PendingIntent.CanceledException' + - 'Exception' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: false + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +formatting: + active: true + android: true +# autoCorrect: true + AnnotationOnSeparateLine: + active: false +# autoCorrect: true + AnnotationSpacing: + active: false +## autoCorrect: true + ArgumentListWrapping: + active: false +## autoCorrect: true + indentSize: 4 +# maxLineLength: 140 + ChainWrapping: + active: false +# autoCorrect: true + CommentSpacing: + active: false +# autoCorrect: true + EnumEntryNameCase: + active: false +# autoCorrect: true + Filename: + active: false + FinalNewline: + active: false +# autoCorrect: true +# insertFinalNewLine: true + ImportOrdering: + active: false +# autoCorrect: true +# layout: '*,java.**,javax.**,kotlin.**,^' + Indentation: + active: false +# autoCorrect: true +# indentSize: 4 +# continuationIndentSize: 4 + MaximumLineLength: + active: true + maxLineLength: 160 + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] +# ignoreBackTickedIdentifier: false +# 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 + maxLineLength: 160 + ParameterWrapping: + active: true + maxLineLength: 160 + PropertyWrapping: + active: true + maxLineLength: 160 + Wrapping: + active: true + # autoCorrect: true + maxLineLength: 160 +# SpacingAroundAngleBrackets: +# active: false +# autoCorrect: true + 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 +# SpacingAroundUnaryOperator: +# active: false +# autoCorrect: true +# SpacingBetweenDeclarationsWithAnnotations: +# active: false +# autoCorrect: true +# SpacingBetweenDeclarationsWithComments: +# active: false +# autoCorrect: true +# StringTemplate: +# active: true +# autoCorrect: true + +naming: + active: true +# BooleanPropertyNaming: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# allowedPattern: '^(is|has|are)' +# ClassNaming: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# parameterPattern: '[a-z][A-Za-z0-9]*' +# privateParameterPattern: '[a-z][A-Za-z0-9]*' +# excludeClassPattern: '$^' +# ignoreOverridden: true +# EnumNaming: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' +# ForbiddenClassName: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# forbiddenName: [] +# FunctionMaxLength: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# maximumFunctionNameLength: 30 +# FunctionMinLength: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# minimumFunctionNameLength: 3 + FunctionNaming: + active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)' +# excludeClassPattern: '$^' +# ignoreOverridden: true +# FunctionParameterNaming: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# parameterPattern: '[a-z][A-Za-z0-9]*' +# excludeClassPattern: '$^' +# ignoreOverridden: true +# InvalidPackageDeclaration: +# active: false +# excludes: ['**/*.kts'] +# rootPackage: '' + MatchingDeclarationName: + active: false + MemberNameEqualsClassName: + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# active: true +# ignoreOverridden: true +# NoNameShadowing: +# active: false +# NonBooleanPropertyPrefixedWithIs: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# ObjectPropertyNaming: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# constantPattern: '[A-Za-z][_A-Za-z0-9]*' +# propertyPattern: '[A-Za-z][_A-Za-z0-9]*' +# privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' + TopLevelPropertyNaming: + active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' +# VariableMaxLength: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# maximumVariableNameLength: 64 +# VariableMinLength: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# minimumVariableNameLength: 1 +# VariableNaming: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# variablePattern: '[a-z][A-Za-z0-9]*' +# privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' +# excludeClassPattern: '$^' +# ignoreOverridden: true + +performance: +# active: true + ArrayPrimitive: + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] +# active: true + ForEachOnRange: + active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + SpreadOperator: + active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# UnnecessaryTemporaryInstantiation: +# active: true + +#potential-bugs: +# active: true +# AvoidReferentialEquality: +# active: false +# forbiddenTypePatterns: +# - 'kotlin.String' +# CastToNullableType: +# active: false +# Deprecation: +# active: false +# DontDowncastCollectionTypes: +# active: false +# DoubleMutabilityForCollection: +# active: false +# DuplicateCaseInWhenExpression: +# active: true +# EqualsAlwaysReturnsTrueOrFalse: +# active: true +# EqualsWithHashCodeExist: +# active: true +# ExitOutsideMain: +# active: false +# ExplicitGarbageCollectionCall: +# active: true +# HasPlatformType: +# active: false +# IgnoredReturnValue: +# active: false +# restrictToAnnotatedMethods: true +# returnValueAnnotations: +# - '*.CheckResult' +# - '*.CheckReturnValue' +# ignoreReturnValueAnnotations: +# - '*.CanIgnoreReturnValue' +# ImplicitDefaultLocale: +# active: true +# ImplicitUnitReturnType: +# active: false +# allowExplicitReturnType: true +# InvalidRange: +# active: true +# IteratorHasNextCallsNextMethod: +# active: true +# IteratorNotThrowingNoSuchElementException: +# active: true +# LateinitUsage: +# active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# ignoreOnClassesPattern: '' +# MapGetWithNotNullAssertionOperator: +# active: false +# MissingWhenCase: +# active: true +# allowElseExpression: true +# NullableToStringCall: +# active: false +# RedundantElseInWhen: +# active: true +# UnconditionalJumpStatementInLoop: +# active: false +# UnnecessaryNotNullOperator: +# active: true +# 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 +# WrongEqualsTypeParameter: +# active: true + +style: + active: true +# ClassOrdering: +# active: false +# CollapsibleIfStatements: +# active: false +# DataClassContainsFunctions: +# active: false +# conversionFunctionPrefix: 'to' +# DataClassShouldBeImmutable: +# active: false + DestructuringDeclarationWithTooManyEntries: + active: false +# maxDestructuringEntries: 3 +# EqualsNullCall: +# active: true +# EqualsOnSignatureLine: +# active: false + ExplicitCollectionElementAccessMethod: + active: true + ExplicitItLambdaParameter: + active: true +# ExpressionBodySyntax: +# active: false +# includeLineWrapping: false + ForbiddenComment: + active: false +# values: +# - 'FIXME:' +# - 'STOPSHIP:' +# - 'TODO:' +# allowedPatterns: '' +# ForbiddenImport: +# active: false +# imports: [] +# forbiddenPatterns: '' +# ForbiddenMethodCall: +# active: false +# methods: +# - 'kotlin.io.print' +# - 'kotlin.io.println' +# ForbiddenPublicDataClass: +# active: true +# excludes: ['**'] +# ignorePackages: +# - '*.internal' +# - '*.internal.*' +# ForbiddenVoid: +# active: false +# ignoreOverridden: false +# ignoreUsageInGenerics: false +# FunctionOnlyReturningConstant: +# active: true +# ignoreOverridableFunction: true +# ignoreActualFunction: true +# excludedFunctions: '' +# LibraryCodeMustSpecifyReturnType: +# active: true +# excludes: ['**'] +# LibraryEntitiesShouldNotBePublic: +# active: true +# excludes: ['**'] +# LoopWithTooManyJumpStatements: +# active: true +# maxJumpCount: 1 + MagicNumber: + active: false +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# ignoreNumbers: +# - '-1' +# - '0' +# - '1' +# - '2' +# ignoreHashCodeFunction: true +# ignorePropertyDeclaration: false +# ignoreLocalVariableDeclaration: false +# ignoreConstantDeclaration: true +# ignoreCompanionObjectPropertyDeclaration: true +# ignoreAnnotation: false +# ignoreNamedArgument: true +# ignoreEnums: false +# ignoreRanges: false +# ignoreExtensionFunctions: true + BracesOnIfStatements: + active: true + MandatoryBracesLoops: + active: true + MaxLineLength: +# active: true + maxLineLength: 120 +# excludePackageStatements: true +# excludeImportStatements: true + excludeCommentStatements: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# MayBeConst: +# active: true +# ModifierOrder: +# active: true +# MultilineLambdaItParameter: +# active: false +# NestedClassesVisibility: +# active: true + NewLineAtEndOfFile: + active: false + NoTabs: + active: true +# ObjectLiteralToLambda: +# active: false +# OptionalAbstractKeyword: +# active: true + OptionalUnit: + active: true +# OptionalWhenBraces: +# active: false +# PreferToOverPairSyntax: +# active: false +# ProtectedMemberInFinalClass: +# active: true + RedundantExplicitType: + active: true +# RedundantHigherOrderMapUsage: +# active: false + RedundantVisibilityModifierRule: + active: true + ReturnCount: + active: false +# max: 2 +# excludedFunctions: 'equals' +# excludeLabeled: false +# excludeReturnFromLambda: true +# excludeGuardClauses: false +# SafeCast: +# active: true +# SerialVersionUIDInSerializableClass: +# active: true + SpacingBetweenPackageAndImports: + active: true + ThrowsCount: + active: true + max: 5 + excludeGuardClauses: false + TrailingWhitespace: + active: false +# UnderscoresInNumericLiterals: +# active: false +# acceptableLength: 4 + UnnecessaryAbstractClass: + active: false +# UnnecessaryAnnotationUseSiteTarget: +# active: false + UnnecessaryApply: + active: true +# UnnecessaryFilter: +# active: false +# UnnecessaryInheritance: +# active: true + UnnecessaryLet: + active: true + UnnecessaryParentheses: + active: false +# UntilInsteadOfRangeTo: +# active: false + UnusedImports: + active: true +# UnusedPrivateClass: +# active: true + UnusedPrivateMember: + active: false +# allowedNames: '(_|ignored|expected|serialVersionUID)' +# UseArrayLiteralsInAnnotations: +# active: false +# UseCheckNotNull: +# active: false +# UseCheckOrError: +# active: false + UseDataClass: + active: false +# allowVars: false +# UseEmptyCounterpart: +# active: false +# UseIfEmptyOrIfBlank: +# active: false +# UseIfInsteadOfWhen: +# active: false +# UseIsNullOrEmpty: +# active: false +# UseOrEmpty: +# active: false +# UseRequire: +# active: false +# UseRequireNotNull: +# active: false +# UselessCallOnNotNull: +# active: true +# UtilityClassWithPublicConstructor: +# active: true + VarCouldBeVal: + active: true +# WildcardImport: +# active: true +# excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] +# excludeImports: +# - 'java.util.*' diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Theme.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Theme.kt index d32917c9..ecc2dc87 100644 --- a/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Theme.kt +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Theme.kt @@ -1,6 +1,5 @@ package co.kr.tnt.designsystem.theme -import android.app.Activity import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme @@ -14,14 +13,13 @@ import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = darkColorScheme( primary = Purple80, secondary = PurpleGrey80, - tertiary = Pink80 + tertiary = Pink80, ) private val LightColorScheme = lightColorScheme( primary = Purple40, secondary = PurpleGrey40, - tertiary = Pink40 - + tertiary = Pink40, /* Other default colors to override background = Color(0xFFFFFBFE), surface = Color(0xFFFFFBFE), @@ -30,7 +28,7 @@ private val LightColorScheme = lightColorScheme( onTertiary = Color.White, onBackground = Color(0xFF1C1B1F), onSurface = Color(0xFF1C1B1F), - */ + */ ) @Composable @@ -38,7 +36,7 @@ fun TnTTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { @@ -53,6 +51,6 @@ fun TnTTheme( MaterialTheme( colorScheme = colorScheme, typography = Typography, - content = content + content = content, ) } diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Type.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Type.kt index 51c7eea8..ead46a4a 100644 --- a/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Type.kt +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/theme/Type.kt @@ -13,8 +13,8 @@ val Typography = Typography( fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) + letterSpacing = 0.5.sp, + ), /* Other default text styles to override titleLarge = TextStyle( fontFamily = FontFamily.Default, @@ -30,5 +30,5 @@ val Typography = Typography( lineHeight = 16.sp, letterSpacing = 0.5.sp ) - */ + */ ) diff --git a/data/src/main/java/co/kr/tnt/data/di/DataModule.kt b/data/src/main/java/co/kr/tnt/data/di/DataModule.kt index 512f55f3..3f2eba64 100644 --- a/data/src/main/java/co/kr/tnt/data/di/DataModule.kt +++ b/data/src/main/java/co/kr/tnt/data/di/DataModule.kt @@ -10,7 +10,6 @@ import dagger.hilt.components.SingletonComponent @InstallIn(SingletonComponent::class) @Module internal abstract class DataModule { - @Binds abstract fun bindsTnTRepository( repository: TnTRepositoryImpl, diff --git a/data/src/main/java/co/kr/tnt/data/model/tnt/request/TnTRequest.kt b/data/src/main/java/co/kr/tnt/data/model/tnt/request/TnTRequest.kt index 57e6f904..3d4de7ce 100644 --- a/data/src/main/java/co/kr/tnt/data/model/tnt/request/TnTRequest.kt +++ b/data/src/main/java/co/kr/tnt/data/model/tnt/request/TnTRequest.kt @@ -11,5 +11,5 @@ data class TnTRequest( ) fun TnT.toRemote(): TnTRequest = TnTRequest( - id = this.id + id = this.id, ) diff --git a/data/src/main/java/co/kr/tnt/data/model/tnt/response/TnTResponse.kt b/data/src/main/java/co/kr/tnt/data/model/tnt/response/TnTResponse.kt index 82b5ead0..dacedc17 100644 --- a/data/src/main/java/co/kr/tnt/data/model/tnt/response/TnTResponse.kt +++ b/data/src/main/java/co/kr/tnt/data/model/tnt/response/TnTResponse.kt @@ -11,5 +11,5 @@ data class TnTResponse( ) fun TnTResponse.toDomain(): TnT = TnT( - id = id + id = id, ) diff --git a/data/src/main/java/co/kr/tnt/data/source/TnTDataSource.kt b/data/src/main/java/co/kr/tnt/data/source/TnTDataSource.kt index 4a205054..37f3566c 100644 --- a/data/src/main/java/co/kr/tnt/data/source/TnTDataSource.kt +++ b/data/src/main/java/co/kr/tnt/data/source/TnTDataSource.kt @@ -3,6 +3,7 @@ package co.kr.tnt.data.source import co.kr.tnt.data.service.TnTService import javax.inject.Inject +@Suppress("UnusedPrivateProperty") internal class TnTDataSource @Inject constructor( private val tntService: TnTService, ) diff --git a/domain/src/main/java/co/kr/tnt/domain/usecase/TnTUseCase.kt b/domain/src/main/java/co/kr/tnt/domain/usecase/TnTUseCase.kt index 4105ea84..83c84ab2 100644 --- a/domain/src/main/java/co/kr/tnt/domain/usecase/TnTUseCase.kt +++ b/domain/src/main/java/co/kr/tnt/domain/usecase/TnTUseCase.kt @@ -3,6 +3,7 @@ package co.kr.tnt.domain.usecase import co.kr.tnt.domain.repository.TnTRepository import javax.inject.Inject +@Suppress("UnusedPrivateProperty") class TnTUseCase @Inject constructor( private val tntRepository: TnTRepository, ) { diff --git a/feature/home/src/main/java/co/kr/tnt/home/HomeScreen.kt b/feature/home/src/main/java/co/kr/tnt/home/HomeScreen.kt index 4bdb6e00..9ed1d6dc 100644 --- a/feature/home/src/main/java/co/kr/tnt/home/HomeScreen.kt +++ b/feature/home/src/main/java/co/kr/tnt/home/HomeScreen.kt @@ -10,9 +10,9 @@ import androidx.hilt.navigation.compose.hiltViewModel @Composable fun HomeScreen( + @Suppress("UnusedParameter") viewModel: HomeViewModel = hiltViewModel(), ) { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Text("home", modifier = Modifier.padding(innerPadding)) } diff --git a/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt b/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt index ca2935c0..f418fce7 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt @@ -24,7 +24,7 @@ class MainActivity : ComponentActivity() { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Greeting( name = "Android", - modifier = Modifier.padding(innerPadding) + modifier = Modifier.padding(innerPadding), ) } } @@ -36,7 +36,7 @@ class MainActivity : ComponentActivity() { fun Greeting(name: String, modifier: Modifier = Modifier) { Text( text = "Hello $name!", - modifier = modifier + modifier = modifier, ) } diff --git a/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt b/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt index 673d03c9..001eeecc 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt @@ -9,9 +9,8 @@ import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor( - private val tntUseCase: TnTUseCase + private val tntUseCase: TnTUseCase, ) : ViewModel() { - init { viewModelScope.launch { tntUseCase() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index af4ed12d..a87e52fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,6 +90,10 @@ inject = "javax.inject:javax.inject:1" junit = { group = "junit", name = "junit", version.ref = "junit" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitJupiter" } +detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } +detekt-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } +ktlint-plugin = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlint" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } @@ -99,3 +103,5 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = " kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }