Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dotenv properties as testable #4

Merged
merged 3 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.6
82 changes: 82 additions & 0 deletions Dangerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#
# GitHub Comment
#
github.dismiss_out_of_range_messages({
error: false,
warning: true,
message: true,
markdown: true
})

#
# File watching
#

[
".idea/codeStyleSettings.xml",
].each do |file|
warn("Are you sure want to modify #{file} ?") if git.modified_files.include?(file)
end

#
# Compiler warnings, errors
#

warning_pattern = /w: (?<path>(?:\/.+)+\.kt): \((?<line>\d+), (?<column>\d+)\): (?<description>.*)/
error_pattern = /e: (?<path>(?:\/.+)+\.kt): \((?<line>\d+), (?<column>\d+)\): (?<description>.*)/

target_files = (git.modified_files - git.deleted_files) + git.added_files
kotlin_compile_files = Dir.glob("**/build/kotlin/compile*Kotlin*.stdout")
unless kotlin_compile_files.empty?
compile_messages = File.read(kotlin_compile_files.first).strip
.split("\n")
.each { |s|
if match = s.match(warning_pattern)
file = Pathname(match[:path]).relative_path_from(Pathname(Dir.pwd)).to_s
if git.diff_for_file(file)
warn("#{match[:description]}", file: file, line: match[:line].to_i)
else
warn("#{file}: (#{match[:line]}, #{match[:column]}): #{match[:description]}")
end
end
if match = s.match(error_pattern)
file = Pathname(match[:path]).relative_path_from(Pathname(Dir.pwd)).to_s
if git.diff_for_file(file)
fail("#{match[:description]}", file: file, line: match[:line].to_i)
else
fail("#{file}: (#{match[:line]}, #{match[:column]}): #{match[:description]}")
end
end
}
end

#
# ktlint
#
checkstyle_format.base_path = Dir.pwd
Dir.glob('**/build/reports/ktlint/ktlint*Check.xml') do |file|
checkstyle_format.report file
end

#
# JUnit test results
#

tests = []
failures = []
errors = []
skipped = []

Dir.glob("**/build/test-results/**/TEST-*.xml") do |file|
junit.parse file
tests.concat(junit.tests)
failures.concat(junit.failures)
errors.concat(junit.errors)
skipped.concat(junit.skipped)
end
junit.tests = tests
junit.failures = failures
junit.errors = errors
junit.skipped = skipped

junit.report
8 changes: 8 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'danger'
gem 'danger-junit'
gem 'danger-checkstyle_format'
70 changes: 70 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
claide (1.0.3)
claide-plugins (0.9.2)
cork
nap
open4 (~> 1.3)
colored2 (3.1.2)
cork (0.3.0)
colored2 (~> 3.1)
danger (7.0.0)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
faraday (>= 0.9.0, < 2.0)
faraday-http-cache (~> 2.0)
git (~> 1.6)
kramdown (~> 2.0)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (~> 4.7)
terminal-table (~> 1)
danger-checkstyle_format (0.1.1)
danger-plugin-api (~> 1.0)
ox (~> 2.0)
danger-junit (1.0.0)
danger (> 2.0)
ox (~> 2.0)
danger-plugin-api (1.0.0)
danger (> 2.0)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
faraday-http-cache (2.2.0)
faraday (>= 0.8)
git (1.6.0)
rchardet (~> 1.8)
kramdown (2.1.0)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
multipart-post (2.1.1)
nap (1.1.0)
no_proxy_fix (0.1.2)
octokit (4.18.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
open4 (1.3.4)
ox (2.13.2)
public_suffix (4.0.4)
rchardet (1.8.0)
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
unicode-display_width (1.7.0)

PLATFORMS
ruby

DEPENDENCIES
danger
danger-checkstyle_format
danger-junit

BUNDLED WITH
2.1.4
9 changes: 9 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ allprojects {
}
}

ktlint {
verbose.set(true)
outputToConsole.set(true)
reporters {
reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE)
}
ignoreFailures.set(true)
}

subprojects {
apply(plugin = "org.jlleitschuh.gradle.ktlint")
ktlint {
Expand Down
24 changes: 24 additions & 0 deletions plugin/src/main/kotlin/co/uzzu/dotenv/EnvProviders.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package co.uzzu.dotenv

/**
* Provides environment variable
*/
interface EnvProvider {
/**
* @return A environment variable for name.
*/
fun getenv(name: String): String?

/**
* @return All environment variables.
*/
fun getenv(): Map<String, String>
}

/**
* EnvProvider implementation using System#getenv
*/
class SystemEnvProvider : EnvProvider {
override fun getenv(name: String): String? = System.getenv(name)
override fun getenv(): Map<String, String> = System.getenv()
}
29 changes: 16 additions & 13 deletions plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package co.uzzu.dotenv.gradle

import co.uzzu.dotenv.DotEnvParser
import co.uzzu.dotenv.EnvProvider
import co.uzzu.dotenv.SystemEnvProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
Expand All @@ -9,29 +11,30 @@ import java.nio.charset.Charset
@Suppress("unused")
class DotEnvPlugin : Plugin<Project> {
override fun apply(target: Project) {
val envTemplate = target.rootProject.envTemplate()
val envSource = target.rootProject.envSource()
val envMerged = envTemplate.keys
.union(envSource.keys)
.map { it to envSource[it] }
val envProvider = SystemEnvProvider()
val dotenvTemplate = target.rootProject.dotenvTemplate()
val dotenvSource = target.rootProject.dotenvSource()
val dotenvMerged = dotenvTemplate.keys
.union(dotenvSource.keys)
.map { it to dotenvSource[it] }
.toMap()

target.applyEnv(envMerged)
target.subprojects { it.applyEnv(envMerged) }
target.applyEnv(envProvider, dotenvMerged)
target.subprojects { it.applyEnv(envProvider, dotenvMerged) }
}

private fun Project.applyEnv(envProperties: Map<String, String?>) {
private fun Project.applyEnv(envProvider: EnvProvider, dotenvProperties: Map<String, String?>) {
val env =
extensions.create("env", DotEnvRoot::class.java, envProperties) as ExtensionAware
envProperties.forEach { (name, value) ->
env.extensions.create(name, DotEnvProperty::class.java, name, value)
extensions.create("env", DotEnvRoot::class.java, envProvider, dotenvProperties) as ExtensionAware
dotenvProperties.forEach { (name, value) ->
env.extensions.create(name, DotEnvProperty::class.java, envProvider, name, value)
}
}

private fun Project.envTemplate(filename: String = ".env.template") =
private fun Project.dotenvTemplate(filename: String = ".env.template"): Map<String, String> =
readText(filename).let(DotEnvParser::parse)

private fun Project.envSource(filename: String = ".env") =
private fun Project.dotenvSource(filename: String = ".env"): Map<String, String> =
readText(filename).let(DotEnvParser::parse)

private fun Project.readText(filename: String): String {
Expand Down
29 changes: 19 additions & 10 deletions plugin/src/main/kotlin/co/uzzu/dotenv/gradle/DotEnvProperties.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package co.uzzu.dotenv.gradle

open class DotEnvRoot(private val map: Map<String, String>) {
import co.uzzu.dotenv.EnvProvider

open class DotEnvRoot(
private val envProvider: EnvProvider,
private val map: Map<String, String>
) {
/**
* @return Indicates an environment variable with specified name is present
*/
fun isPresent(name: String): Boolean =
System.getenv()[name]?.let { true }
envProvider.getenv()[name]?.let { true }
?: map[name]?.let { true }
?: false

Expand All @@ -14,7 +19,7 @@ open class DotEnvRoot(private val map: Map<String, String>) {
* @throws IllegalStateException if it was not set
*/
fun fetch(name: String) =
System.getenv()[name]
envProvider.getenv()[name]
?: map[name]
?: throw IllegalStateException("""Environment variable $name was not set.""")

Expand All @@ -23,25 +28,29 @@ open class DotEnvRoot(private val map: Map<String, String>) {
* @throws IllegalStateException if it was not set
*/
fun fetch(name: String, defaultValue: String) =
System.getenv()[name]
envProvider.getenv()[name]
?: map[name]
?: defaultValue

/**
* @return An environment variable. If it was not set, returns specified default value
*/
fun fetchOrNull(name: String): String? =
System.getenv()[name]
envProvider.getenv()[name]
?: map[name]
}

open class DotEnvProperty(private val name: String, private val dotenvValue: String?) {
open class DotEnvProperty(
private val envProvider: EnvProvider,
private val name: String,
private val dotenvValue: String?
) {

/**
* @return Indicates an environment variable is present
*/
val isPresent: Boolean
get() = System.getenv()[name]?.let { true }
get() = envProvider.getenv()[name]?.let { true }
?: dotenvValue?.let { true }
?: false

Expand All @@ -51,22 +60,22 @@ open class DotEnvProperty(private val name: String, private val dotenvValue: Str
*/
val value: String
get() =
System.getenv()[name]
envProvider.getenv()[name]
?: dotenvValue
?: throw IllegalStateException("""Environment variable $name was not set.""")

/**
* @return An environment variable. If it was not set, returns specified default value
*/
fun orElse(defaultValue: String): String =
System.getenv()[name]
envProvider.getenv()[name]
?: dotenvValue
?: defaultValue

/**
* @return An environment variable. If it was not set, returns null.
*/
fun orNull(): String? =
System.getenv()[name]
envProvider.getenv()[name]
?: dotenvValue
}
8 changes: 8 additions & 0 deletions plugin/src/test/kotlin/co/uzzu/dotenv/InMemoryEnvProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package co.uzzu.dotenv

class InMemoryEnvProvider(
private val map: Map<String, String>
) : EnvProvider {
override fun getenv(name: String): String? = map[name]
override fun getenv(): Map<String, String> = map
}
Loading