diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 5790efb..b658789 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -33,7 +33,7 @@ jobs: - name: Run reviewdog if: always() run: | - find . -type f -name "ktlint*Check.xml" -exec sh -c "cat {} | reviewdog -f=checkstyle -name='ktlint' -reporter=github-pr-review" \; + cat build/reports/detekt/detekt-merged-report.sarif | reviewdog -f=sarif -name="detekt" -reporter="github-check" -level="error" -filter-mode="nofilter" -fail-on-error - name: Gradle publish to mavenLocal run: | ./gradlew publishToMavenLocal diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e3ca0..a88e9e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,14 +17,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +## [4.0.0] - 2023-12-22 + +### Changed + +- Use Gradle 8.5 +- Use Kotlin 1.9.21 + +### Removed + +- `val (Map) env.allVariables` + - Replace to use a method `(Map) env.allVariables()` instead. + ## [3.0.0] - 2023-11-27 ### Changed -- The behavior of project to ignore the filename option specified for this plugin in the parent project's gradle properties by default. + +- The behavior of project to ignore the filename option specified for this plugin in the parent project's gradle + properties by default. - Fix of [#39](https://github.com/uzzu/dotenv-gradle/issues/39) - - For example, if `dotenv.filename=.env.staging` is set in the root project, this setting will automatically apply to sub-projects as well. While this follows the correct resolution order of Gradle Properties, it has been a source of confusion for users working with dotenv. - - To disable this default behavior, add `dotenv.filename.ignore.parent=false` to the gradle.properties in the root project. - - A same update has been applied to the feature of changing `.env.template` filename. To disable this default behavior, add `dotenv.template.filename.ignore.parent=false` to the gradle.properties in the root project. + - For example, if `dotenv.filename=.env.staging` is set in the root project, this setting will automatically apply to + sub-projects as well. While this follows the correct resolution order of Gradle Properties, it has been a source of + confusion for users working with dotenv. + - To disable this default behavior, add `dotenv.filename.ignore.parent=false` to the gradle.properties in the root + project. + - A same update has been applied to the feature of changing `.env.template` filename. To disable this default + behavior, add `dotenv.template.filename.ignore.parent=false` to the gradle.properties in the root project. ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 77d4230..3a7c8dd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,33 +1,100 @@ +import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.report.ReportMergeTask +import kotlin.streams.asSequence +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths + plugins { base - id("co.uzzu.dotenv.gradle") version "3.0.0" - kotlin("jvm") version "1.4.31" apply false - id("org.jlleitschuh.gradle.ktlint") version "11.0.0" + alias(libs.plugins.dotenv.gradle) + alias(libs.plugins.detekt) + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.gradle.plugin.publish) apply false +} + +val reportMerge by tasks.registering(ReportMergeTask::class) { + output.set(rootProject.layout.buildDirectory.file("reports/detekt/detekt-merged-report.sarif")) +} + +detektConfigurationRoot(reportMerge) + +subprojects { + apply(plugin = "io.gitlab.arturbosch.detekt") + detektConfigurationShared(reportMergeTask = reportMerge) +} + +// region detekt configuration + +fun Project.detektConfigurationRoot( + reportMergeTask: TaskProvider, +) { + val allKtsFiles = allKtsFiles() + detektConfigurationShared( + reportMergeTask = reportMergeTask, + source = allKtsFiles + + allBuildSrcKtFiles() + + files("src"), + ) } -allprojects { - repositories { - mavenCentral() +fun Project.detektConfigurationShared( + reportMergeTask: TaskProvider, + source: List = listOf(files("src")), + detektConfig: File = rootProject.file("./gradle/detekt.yml"), +) { + detekt { + buildUponDefaultConfig = true + config.setFrom(detektConfig) + this.source.setFrom(source) + ignoreFailures = false + debug = false + parallel = true + } + + tasks.withType().configureEach { + finalizedBy(reportMerge) + reports.sarif.required = true + } + + reportMergeTask { + input.from(tasks.withType().map { it.sarifReportFile }) } } -ktlint { - verbose.set(true) - outputToConsole.set(true) - reporters { - reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE) +fun Project.allBuildSrcKtFiles(): List { + if (!file(rootProject.projectDir.path + "/buildSrc").exists()) { + return emptyList() } - ignoreFailures.set(true) + val ignoringPath = listOf(".git/", "build/", ".gradle/") + val ktPattern = "glob:**/*.kt" + val ktsPattern = "glob:**/*.kts" + val ktMatcher = FileSystems.getDefault().getPathMatcher(ktPattern) + val ktsMatcher = FileSystems.getDefault().getPathMatcher(ktsPattern) + val results = Files.walk(Paths.get(rootProject.projectDir.path + "/buildSrc")) + .asSequence() + .filter { + val path = it.toString() + !ignoringPath.contains(path) && + (ktMatcher.matches(it) || ktsMatcher.matches(it)) + } + .toList() + return results } -subprojects { - apply(plugin = "org.jlleitschuh.gradle.ktlint") - ktlint { - verbose.set(true) - outputToConsole.set(true) - reporters { - reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE) +fun Project.allKtsFiles(): List { + val ignoringPath = listOf(".git/", "build/", ".gradle/", "src/") + val pattern = "glob:**/*.kts" + val matcher = FileSystems.getDefault().getPathMatcher(pattern) + val results = Files.walk(Paths.get(projectDir.path)) + .asSequence() + .filter { + val path = it.toString() + !ignoringPath.contains(path) && matcher.matches(it) } - ignoreFailures.set(true) - } + .toList() + return results } + +// endregion diff --git a/examples/README.md b/examples/README.md index dda342d..894ff99 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,4 +2,5 @@ - [Basic Usage](/examples/basic) - [Change `.env` filename](/examples/change_file) +- [Change `.env.template` filename](/examples/change_template_file) - [Hierarchical dotenv definitions](/examples/hierarchical_definitions) diff --git a/examples/basic/build.gradle.kts b/examples/basic/build.gradle.kts index 4c6eb04..f1c218b 100644 --- a/examples/basic/build.gradle.kts +++ b/examples/basic/build.gradle.kts @@ -1,6 +1,6 @@ plugins { base - id("co.uzzu.dotenv.gradle") version "3.0.0" + id("co.uzzu.dotenv.gradle") version "4.0.0" } val keys = listOf( diff --git a/examples/basic/sub/build.gradle.kts b/examples/basic/sub/build.gradle.kts index 47ff8f9..a1631da 100644 --- a/examples/basic/sub/build.gradle.kts +++ b/examples/basic/sub/build.gradle.kts @@ -1,3 +1,10 @@ +val keys = listOf( + "FOO", + "BAR", + "BAZ", + "QUX" +) + println("""[$name] ${env.FOO.orElse("default_foo")}""") println("""[$name] ${env.BAR.orNull()}""") try { @@ -8,4 +15,12 @@ try { println("""[$name] ${env.QUX.value}""") // All environment variables which are merged with variables specified in .env files. -env.allVariables +print("[$name] #allVariables() (filtered by keys in .env.template and .env): ") +println(env.allVariables().filterKeys { keys.contains(it) }) + +// All environment variables which are merged with variables specified in .env files includes null. +// The Plugin set key if defined in .env template files, but it could not be retrieved as nullable value entries by using allVariables() +// By using allVariablesOrNull instead of allVariables, it is possible to retrieve all environment variables, including those that are only defined in the .env template (which means their values are null). +env.allVariablesOrNull() +print("[$name] #allVariablesOrNull() (filtered by keys in .env.template and .env): ") +println(env.allVariablesOrNull().filterKeys { keys.contains(it) }) diff --git a/examples/change_file/build.gradle.kts b/examples/change_file/build.gradle.kts index a87e65e..b2f73f6 100644 --- a/examples/change_file/build.gradle.kts +++ b/examples/change_file/build.gradle.kts @@ -1,6 +1,6 @@ plugins { base - id("co.uzzu.dotenv.gradle") version "3.0.0" + id("co.uzzu.dotenv.gradle") version "4.0.0" } println(env.FOO.value) diff --git a/examples/change_template_file/build.gradle.kts b/examples/change_template_file/build.gradle.kts index 29109c4..2cc2640 100644 --- a/examples/change_template_file/build.gradle.kts +++ b/examples/change_template_file/build.gradle.kts @@ -1,6 +1,6 @@ plugins { base - id("co.uzzu.dotenv.gradle") version "3.0.0" + id("co.uzzu.dotenv.gradle") version "4.0.0" } val keys = listOf( diff --git a/examples/hierarchical_definitions/build.gradle.kts b/examples/hierarchical_definitions/build.gradle.kts index 74e948e..bb9a7e2 100644 --- a/examples/hierarchical_definitions/build.gradle.kts +++ b/examples/hierarchical_definitions/build.gradle.kts @@ -1,6 +1,6 @@ plugins { base - id("co.uzzu.dotenv.gradle") version "3.0.0" + id("co.uzzu.dotenv.gradle") version "4.0.0" } println("[$name] FOO: ${env.FOO.value}") diff --git a/gradle/detekt.yml b/gradle/detekt.yml new file mode 100644 index 0000000..c7362dd --- /dev/null +++ b/gradle/detekt.yml @@ -0,0 +1,792 @@ +build: + maxIssues: 0 + excludeCorrectable: false + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +config: + validation: true + warningsAsErrors: true + checkExhaustiveness: true + # 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' + - 'HtmlOutputReport' + - 'MdOutputReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: true + EndOfSentenceFormat: + active: false + endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + KDocReferencesNonPublicProperty: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + OutdatedDocumentation: + active: true + matchTypeParameters: true + matchDeclarationsOrder: true + allowParamOnConstructorProperties: false + UndocumentedPublicClass: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + searchInProtectedClass: false + UndocumentedPublicFunction: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + searchProtectedFunction: false + UndocumentedPublicProperty: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + searchProtectedProperty: false + +complexity: + active: true + CognitiveComplexMethod: + active: false + threshold: 15 + ComplexCondition: + active: true + threshold: 3 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + ignoreOverloaded: false + CyclomaticComplexMethod: + active: true + threshold: 14 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [ ] + LargeClass: + active: false + threshold: 600 + LongMethod: + active: false + threshold: 60 + LongParameterList: + active: true + functionThreshold: 16 + constructorThreshold: 16 + ignoreDefaultParameters: true + ignoreDataClasses: true + ignoreAnnotatedParameter: [ ] + MethodOverloading: + active: true + threshold: 3 + NamedArguments: + active: false + threshold: 3 + ignoreArgumentsMatchingNames: false + NestedBlockDepth: + active: true + threshold: 4 + NestedScopeFunctions: + active: false + threshold: 1 + functions: + - 'kotlin.apply' + - 'kotlin.run' + - 'kotlin.with' + - 'kotlin.let' + - 'kotlin.also' + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + threshold: 2 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + thresholdInFiles: 11 + thresholdInClasses: 11 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + ignorePrivate: false + ignoreOverridden: false + +coroutines: + active: true + GlobalCoroutineUsage: + active: true + InjectDispatcher: + active: true + dispatcherNames: + - 'Main' + - 'IO' + - 'Default' + - 'Unconfined' + RedundantSuspendModifier: + active: true + SleepInsteadOfDelay: + active: true + SuspendFunSwallowedCancellation: + active: true + SuspendFunWithCoroutineScopeReceiver: + active: false + SuspendFunWithFlowReturnType: + active: true + +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: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: true + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: true + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +naming: + active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are|should)' + ClassNaming: + active: true + classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + privateParameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + EnumNaming: + active: true + enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: true + forbiddenName: + - '*Manager' + - '*Controller' + - '*Util' + - '*Utils' + - '*Helper' + - '*Model' + - '*Dto' + - '*DTO' + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + functionPattern: '[a-zA-Z][a-zA-Z0-9]*' + excludeClassPattern: '$^' + FunctionParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + InvalidPackageDeclaration: + active: true + rootPackage: '' + requireRootInDeclaration: false + LambdaParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*|_' + MatchingDeclarationName: + active: false + mustBeFirst: true + MemberNameEqualsClassName: + active: true + ignoreOverridden: true + NoNameShadowing: + active: true + NonBooleanPropertyPrefixedWithIs: + active: true + ObjectPropertyNaming: + active: true + constantPattern: '[A-Z][A-Za-z0-9]*' + propertyPattern: '[A-Za-z][A-Za-z0-9]*' + privatePropertyPattern: '[A-Za-z][A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '[a-z]+(\.[a-z][a-z0-9]*)*' + TopLevelPropertyNaming: + active: true + constantPattern: '[A-Z][A-Za-z0-9]*' + propertyPattern: '[A-Za-z][A-Za-z0-9]*' + privatePropertyPattern: '[A-Za-z][A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: true + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + +performance: + active: true + ArrayPrimitive: + active: true + CouldBeSequence: + active: true + threshold: 3 + ForEachOnRange: + active: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + SpreadOperator: + active: false + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + UnnecessaryPartOfBinaryExpression: + active: true + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + AvoidReferentialEquality: + active: true + forbiddenTypePatterns: + - 'kotlin.String' + CastNullableToNonNullableType: + active: true + CastToNullableType: + active: true + Deprecation: + active: true + DontDowncastCollectionTypes: + active: true + DoubleMutabilityForCollection: + active: true + 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' + ElseCaseInsteadOfExhaustiveWhen: + active: false + ignoredSubjectTypes: [ ] + EqualsAlwaysReturnsTrueOrFalse: + active: true + EqualsWithHashCodeExist: + active: true + ExitOutsideMain: + active: true + ExplicitGarbageCollectionCall: + active: true + HasPlatformType: + active: true + IgnoredReturnValue: + active: true + restrictToConfig: true + returnValueAnnotations: + - 'CheckResult' + - '*.CheckResult' + - 'CheckReturnValue' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - 'CanIgnoreReturnValue' + - '*.CanIgnoreReturnValue' + returnValueTypes: + - 'kotlin.sequences.Sequence' + - 'kotlinx.coroutines.flow.*Flow' + - 'java.util.stream.*Stream' + ignoreFunctionCall: [ ] + 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/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + ignoreOnClassesPattern: '' + MapGetWithNotNullAssertionOperator: + active: true + MissingPackageDeclaration: + active: true + excludes: [ '**/*.kts' ] + NullCheckOnMutableProperty: + active: true + NullableToStringCall: + active: true + PropertyUsedBeforeDeclaration: + active: false + UnconditionalJumpStatementInLoop: + active: true + UnnecessaryNotNullCheck: + active: true + UnnecessaryNotNullOperator: + active: true + UnnecessarySafeCall: + active: true + UnreachableCatchBlock: + active: true + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] + UnsafeCast: + active: true + UnusedUnaryOperator: + active: true + UselessPostfixExpression: + active: true + WrongEqualsTypeParameter: + active: true + +style: + active: true + AlsoCouldBeApply: + active: true + BracesOnIfStatements: + active: true + singleLine: 'always' + multiLine: 'always' + BracesOnWhenStatements: + active: true + singleLine: 'always' + multiLine: 'always' + CanBeNonNullable: + active: false + CascadingCallWrapping: + active: false + includeElvis: true + ClassOrdering: + active: true + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: + - 'to' + allowOperators: false + DataClassShouldBeImmutable: + active: true + DestructuringDeclarationWithTooManyEntries: + active: true + maxDestructuringEntries: 3 + DoubleNegativeLambda: + active: true + negativeFunctions: + - reason: 'Use `takeIf` instead.' + value: 'takeUnless' + - reason: 'Use `all` instead.' + value: 'none' + negativeFunctionNameParts: + - 'not' + - 'non' + EqualsNullCall: + active: true + EqualsOnSignatureLine: + active: false + ExplicitCollectionElementAccessMethod: + active: true + ExplicitItLambdaParameter: + active: true + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenAnnotation: + active: true + annotations: + - reason: 'it is a java annotation. Use `Suppress` instead.' + value: 'java.lang.SuppressWarnings' + - reason: 'it is a java annotation. Use `kotlin.Deprecated` instead.' + value: 'java.lang.Deprecated' + - reason: 'it is a java annotation. Use `kotlin.annotation.MustBeDocumented` instead.' + value: 'java.lang.annotation.Documented' + - reason: 'it is a java annotation. Use `kotlin.annotation.Target` instead.' + value: 'java.lang.annotation.Target' + - reason: 'it is a java annotation. Use `kotlin.annotation.Retention` instead.' + value: 'java.lang.annotation.Retention' + - reason: 'it is a java annotation. Use `kotlin.annotation.Repeatable` instead.' + value: 'java.lang.annotation.Repeatable' + - reason: 'Kotlin does not support @Inherited annotation, see https://youtrack.jetbrains.com/issue/KT-22265' + value: 'java.lang.annotation.Inherited' + ForbiddenComment: + active: true + comments: + - reason: 'Forbidden FIXME todo marker in comment, please fix the problem.' + value: 'FIXME:' + - reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.' + value: 'STOPSHIP:' + - reason: 'Forbidden TODO todo marker in comment, please do the changes.' + value: 'TODO:' + allowedPatterns: '' + ForbiddenImport: + active: true + imports: [ ] + forbiddenPatterns: '' + ForbiddenMethodCall: + active: true + methods: + - reason: 'print does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.print' + - reason: 'println does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.println' + ForbiddenSuppress: + active: false + rules: [ ] + ForbiddenVoid: + active: true + ignoreOverridden: false + ignoreUsageInGenerics: false + FunctionOnlyReturningConstant: + active: true + ignoreOverridableFunction: true + ignoreActualFunction: true + excludedFunctions: [ ] + LoopWithTooManyJumpStatements: + active: false + maxJumpCount: 1 + MagicNumber: + active: true + excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts' ] + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + ignoreHashCodeFunction: true + ignorePropertyDeclaration: true + ignoreLocalVariableDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: true + ignoreNamedArgument: true + ignoreEnums: false + ignoreRanges: false + ignoreExtensionFunctions: true + MandatoryBracesLoops: + active: true + MaxChainedCallsOnSameLine: + active: true + maxChainedCalls: 5 + MaxLineLength: + active: true + maxLineLength: 128 + excludePackageStatements: true + excludeImportStatements: true + excludeCommentStatements: true + excludeRawStrings: true + MayBeConst: + active: true + ModifierOrder: + active: true + MultilineLambdaItParameter: + active: false + MultilineRawStringIndentation: + active: true + indentSize: 0 + trimmingMethods: + - 'trimIndent' + - 'trimMargin' + NestedClassesVisibility: + active: true + NewLineAtEndOfFile: + active: true + NoTabs: + active: true + NullableBooleanCheck: + active: true + ObjectLiteralToLambda: + active: true + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: true + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: true + RedundantExplicitType: + active: true + RedundantHigherOrderMapUsage: + active: true + RedundantVisibilityModifierRule: + active: true + ReturnCount: + active: true + max: 2 + excludedFunctions: + - 'equals' + excludeLabeled: false + excludeReturnFromLambda: true + excludeGuardClauses: true + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: true + SpacingBetweenPackageAndImports: + active: true + StringShouldBeRawString: + active: true + maxEscapedCharacterCount: 2 + ignoredCharacters: [ ] + ThrowsCount: + active: true + max: 2 + excludeGuardClauses: true + TrailingWhitespace: + active: true + TrimMultilineRawString: + active: true + trimmingMethods: + - 'trimIndent' + - 'trimMargin' + UnderscoresInNumericLiterals: + active: true + acceptableLength: 4 + allowNonStandardGrouping: false + UnnecessaryAbstractClass: + active: true + UnnecessaryAnnotationUseSiteTarget: + active: true + UnnecessaryApply: + active: true + UnnecessaryBackticks: + active: true + UnnecessaryBracesAroundTrailingLambda: + active: true + UnnecessaryFilter: + active: true + UnnecessaryInheritance: + active: true + UnnecessaryInnerClass: + active: true + UnnecessaryLet: + active: true + UnnecessaryParentheses: + active: true + allowForUnclearPrecedence: false + UntilInsteadOfRangeTo: + active: true + UnusedImports: + active: true + UnusedParameter: + active: true + allowedNames: 'ignored|expected' + UnusedPrivateClass: + active: true + UnusedPrivateMember: + active: true + allowedNames: '' + ignoreAnnotated: + - 'Preview' + UnusedPrivateProperty: + active: true + allowedNames: '_|ignored|expected|serialVersionUID' + UseAnyOrNoneInsteadOfFind: + active: true + UseArrayLiteralsInAnnotations: + active: true + UseCheckNotNull: + active: true + UseCheckOrError: + active: true + UseDataClass: + active: true + allowVars: false + UseEmptyCounterpart: + active: false + UseIfEmptyOrIfBlank: + active: false + UseIfInsteadOfWhen: + active: false + ignoreWhenContainingVariableDeclaration: false + UseIsNullOrEmpty: + active: true + UseLet: + active: false + UseOrEmpty: + active: true + UseRequire: + active: true + UseRequireNotNull: + active: true + UseSumOfInsteadOfFlatMapSize: + active: true + UselessCallOnNotNull: + active: true + UtilityClassWithPublicConstructor: + active: true + VarCouldBeVal: + active: true + ignoreLateinitVar: false + WildcardImport: + active: true + excludeImports: [ ] diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..4aa22fb --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,24 @@ +[versions] +java-toolchain = "8" + +dotenv-gradle = "3.0.0" +kotlin = "1.9.21" +gradle-plugin-publish = "1.2.1" +detekt = "1.23.4" + +junit-bom = "5.10.1" +assertk = "0.28.0" + +[plugins] +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +dotenv-gradle = { id = "co.uzzu.dotenv.gradle", version.ref = "dotenv-gradle" } +gradle-plugin-publish = { id = "com.gradle.plugin-publish", version.ref = "gradle-plugin-publish" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } + +[libraries] +junit-bom = { module = "org.junit:junit-bom", version.ref = "junit-bom" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine" } +junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } +assertk = { module = "com.willowtreeapps.assertk:assertk", version.ref = "assertk" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 05679dc..a595206 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..744e882 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index e3b9da9..2fd68ef 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,36 +1,38 @@ plugins { - id("com.gradle.plugin-publish") version "0.11.0" `java-gradle-plugin` `maven-publish` - kotlin("jvm") + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.gradle.plugin.publish) } dependencies { compileOnly(gradleApi()) testImplementation(gradleTestKit()) - testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.10.1") - testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.1") - testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") + testImplementation(platform(libs.junit.bom)) + testImplementation(libs.junit.jupiter.api) + testRuntimeOnly(libs.junit.jupiter.engine) + testRuntimeOnly(libs.junit.vintage.engine) + testRuntimeOnly(libs.junit.platform.launcher) + testImplementation(libs.assertk) } -configure { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - - sourceSets { - getByName("main").java.srcDirs("src/main/kotlin") - getByName("test").java.srcDirs("src/test/kotlin") +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(libs.versions.java.toolchain.get().toInt())) } } +sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + getByName("test").java.srcDirs("src/test/kotlin") +} + tasks { compileKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = JavaVersion.toVersion(libs.versions.java.toolchain.get()).toString() } compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = JavaVersion.toVersion(libs.versions.java.toolchain.get()).toString() } test { useJUnitPlatform() @@ -40,51 +42,38 @@ tasks { // region publishing object Artifact { - val groupId = "co.uzzu.dotenv" - val artifactId = "gradle" - val version = "3.0.0" + const val GroupId = "co.uzzu.dotenv" + const val ArtifactId = "gradle" + const val Version = "4.0.0" } -group = Artifact.groupId -version = Artifact.version +group = Artifact.GroupId +version = Artifact.Version -gradlePlugin { - plugins { - register("dotenv") { - id = "co.uzzu.dotenv.gradle" - implementationClass = "co.uzzu.dotenv.gradle.DotEnvPlugin" +publishing { + publishing { + repositories { + mavenLocal() + } + + publications.create("pluginMaven", MavenPublication::class) { + artifactId = Artifact.ArtifactId } } } -pluginBundle { +@Suppress("UnstableApiUsage") +gradlePlugin { website = "https://github.com/uzzu/dotenv-gradle" vcsUrl = "https://github.com/uzzu/dotenv-gradle.git" - description = "A converting plugin from dotenv(.env.template, .env) files to Gradle project extension" - tags = listOf("dotenv") - (plugins) { - "dotenv" { + plugins { + create("dotenv") { + id = "co.uzzu.dotenv.gradle" + implementationClass = "co.uzzu.dotenv.gradle.DotEnvPlugin" displayName = "Gradle dotenv plugin" - version = Artifact.version - } - } - - mavenCoordinates { - groupId = Artifact.groupId - artifactId = Artifact.artifactId - version = Artifact.version - } -} - -publishing { - publishing { - repositories { - mavenLocal() - } - - publications.create("pluginMaven", MavenPublication::class) { - artifactId = Artifact.artifactId + description = "A converting plugin from dotenv(.env.template, .env) files to Gradle project extension" + tags = listOf("dotenv") } } } diff --git a/plugin/src/main/kotlin/co/uzzu/dotenv/DotEnvParser.kt b/plugin/src/main/kotlin/co/uzzu/dotenv/DotEnvParser.kt index 6ee288e..90117e7 100644 --- a/plugin/src/main/kotlin/co/uzzu/dotenv/DotEnvParser.kt +++ b/plugin/src/main/kotlin/co/uzzu/dotenv/DotEnvParser.kt @@ -1,7 +1,7 @@ package co.uzzu.dotenv object DotEnvParser { - private const val newLine = "\n" + private const val NewLine = "\n" private val newLinesRegex = Regex("""\\n""", option = RegexOption.MULTILINE) private val keyValRegex = Regex("""^\s*([\w.-]+)\s*=\s*(.*)?\s*$""") private val newLinesMatches = Regex("""\n|\r|\r\n""") @@ -23,7 +23,7 @@ object DotEnvParser { val trimmedValue = if (isDoubleQuoted || isSingleQuoted) { val dequoted = rawValue.substring(1, rawValue.lastIndex) if (isDoubleQuoted) { - dequoted.replace(newLinesRegex, newLine) + dequoted.replace(newLinesRegex, NewLine) } else { dequoted } diff --git a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt index ff0f5ae..52ba67d 100644 --- a/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt +++ b/plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt @@ -9,21 +9,6 @@ open class DotEnvRoot( private val envProvider: EnvProvider, private val dotenvMap: Map ) { - /** - * @return All environment variables which are merged with variables specified in .env files. - */ - @Deprecated("Replace to use DotEnvRoot#allVariables()") - val allVariables: Map - get() { - val results = envProvider.getenv().toMutableMap() - dotenvMap.forEach { (key, value) -> - if (value != null && results[key] == null) { - results[key] = value - } - } - return results.toMap() - } - /** * @return Indicates an environment variable with specified name is present */ @@ -39,7 +24,7 @@ open class DotEnvRoot( fun fetch(name: String) = envProvider.getenv()[name] ?: dotenvMap[name] - ?: throw IllegalStateException("""Environment variable $name was not set.""") + ?: error("""Environment variable $name was not set.""") /** * @return An environment variable @@ -112,7 +97,7 @@ open class DotEnvProperty( get() = envProvider.getenv()[name] ?: dotenvValue - ?: throw IllegalStateException("""Environment variable $name was not set.""") + ?: error("""Environment variable $name was not set.""") /** * @return An environment variable. If it was not set, returns specified default value diff --git a/plugin/src/test/kotlin/co/uzzu/dotenv/DotEnvParserTest.kt b/plugin/src/test/kotlin/co/uzzu/dotenv/DotEnvParserTest.kt index fba569a..890a917 100644 --- a/plugin/src/test/kotlin/co/uzzu/dotenv/DotEnvParserTest.kt +++ b/plugin/src/test/kotlin/co/uzzu/dotenv/DotEnvParserTest.kt @@ -9,8 +9,8 @@ class DotEnvParserTest { @Test fun testBasicParse() { val text = """ - HOGE_API_KEY="dummy_key" - HOGE_API_SECRET="dummy_secret" + HOGE_API_KEY="dummy_key" + HOGE_API_SECRET="dummy_secret" """.trimIndent() val actual = DotEnvParser.parse(text) @@ -23,8 +23,8 @@ class DotEnvParserTest { @Test fun emptyValue() { val text = """ - HOGE_API_KEY= - HOGE_API_SECRET= + HOGE_API_KEY= + HOGE_API_SECRET= """.trimIndent() val actual = DotEnvParser.parse(text) @@ -37,8 +37,8 @@ class DotEnvParserTest { @Test fun quotedValue() { val text = """ - HOGE_API_KEY="dummy_key" - HOGE_API_SECRET='dummy_secret' + HOGE_API_KEY="dummy_key" + HOGE_API_SECRET='dummy_secret' """.trimIndent() val actual = DotEnvParser.parse(text) @@ -51,8 +51,8 @@ class DotEnvParserTest { @Test fun incompleteQuoteValue() { val text = """ - HOGE_API_KEY="dummy_key - HOGE_API_SECRET=dummy_secret' + HOGE_API_KEY="dummy_key + HOGE_API_SECRET=dummy_secret' """.trimIndent() val actual = DotEnvParser.parse(text) @@ -65,8 +65,8 @@ class DotEnvParserTest { @Test fun singleCharQuoteValue() { val text = """ - HOGE_API_KEY=" - HOGE_API_SECRET=' + HOGE_API_KEY=" + HOGE_API_SECRET=' """.trimIndent() val actual = DotEnvParser.parse(text) diff --git a/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/HierarchicalDotEnvDefinitionsTest.kt b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/HierarchicalDotEnvDefinitionsTest.kt index 470eaf8..08a7a74 100644 --- a/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/HierarchicalDotEnvDefinitionsTest.kt +++ b/plugin/src/test/kotlin/co/uzzu/dotenv/gradle/HierarchicalDotEnvDefinitionsTest.kt @@ -88,7 +88,7 @@ class HierarchicalDotEnvDefinitionsTest { file( ".env", """ - HOGE=100 + HOGE=100 """.trimIndent() ) directory("sub") diff --git a/settings.gradle.kts b/settings.gradle.kts index 2cb0880..1c03a20 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,18 @@ +@file:Suppress("UnstableApiUsage") + +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + } +} + rootProject.name = "dotenv-gradle" include("plugin")