Skip to content

Added DotEnvConditionChecker#8276

Open
Andrii-Danylenko wants to merge 6 commits intodevfrom
feature/implement-dotenv-checker-to-prevent-unexpected-behaviour-
Open

Added DotEnvConditionChecker#8276
Andrii-Danylenko wants to merge 6 commits intodevfrom
feature/implement-dotenv-checker-to-prevent-unexpected-behaviour-

Conversation

@Andrii-Danylenko
Copy link
Member

@Andrii-Danylenko Andrii-Danylenko commented Mar 26, 2025

DotEnvConditionChecker will now detect the presence of a dotenv file and automatically create a bean accordingly. This will prevent unexpected behaviour the need of changing code later.

Summary by CodeRabbit

  • New Features

    • Introduced a new class for dynamic environment checks that conditionally activate application functionalities.
    • Added a test class to validate the functionality of the new environment check class.
  • Refactor

    • Enhanced configuration logic for environment beans, allowing for more nuanced control over their instantiation based on application conditions.

…and automatically create a bean accordingly.
@Andrii-Danylenko Andrii-Danylenko self-assigned this Mar 26, 2025
@coderabbitai
Copy link

coderabbitai bot commented Mar 26, 2025

Walkthrough

This pull request introduces a new class, DotEnvConditionChecker, which includes a static method isEnabled() to verify the existence of a dotenv file in the user's directory. Additionally, the DotenvConfig class has been relocated to a more specific dotenv package and updated with new annotations for conditional bean registration based on the isEnabled() method. The changes enhance the configuration logic for the Dotenv beans, allowing for more nuanced instantiation control.

Changes

File(s) Change Summary
service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java Added new class DotEnvConditionChecker with a public static method isEnabled() that checks for the existence of a dotenv file using Java’s file handling classes.
service/src/main/java/greencity/config/dotenv/DotenvConfig.java Moved from package greencity.config to greencity.config.dotenv; updated bean registration in the dotenv() method to use a SpEL expression with DotEnvConditionChecker.isEnabled(), added @Primary annotation, and retained conditional registration for fallbackDotenv().
service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java Added new test class DotEnvConditionCheckerTest to validate the functionality of isEnabled() with various test cases.

Suggested labels

back-end, java

Suggested reviewers

  • oleksandra-bulhakova
  • maks741
  • Cr1stal423

Poem

A file is checked, a bean is born,
In lines of code through dusk and morn.
DotEnv watches, true and clear,
Guiding beans to persevere.
With logic sound and code so neat,
Our configuration sings a beat! 🎶
Cheers to change in every feat!


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9b34ca and fc48c5f.

📒 Files selected for processing (1)
  • service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java (2)

9-13: The implementation is simple and functional, but consider some improvements

The class correctly checks for the existence of the dotenv file, which aligns with the PR objectives. However, a few enhancements could make this more robust:

  1. Consider adding error handling for potential SecurityException when accessing files
  2. The static method approach makes testing difficult - consider making this a Spring component with an injectable method for better testability
 package greencity.config.dotenv;

 import greencity.constant.AppConstant;

 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import org.springframework.stereotype.Component;

+@Component
 public class DotEnvConditionChecker {
-    public static boolean isEnabled() {
-        return Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + AppConstant.DOTENV_FILENAME));
+    public boolean isEnabled() {
+        try {
+            return Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + AppConstant.DOTENV_FILENAME));
+        } catch (SecurityException e) {
+            // Log the exception if needed
+            return false;
+        }
     }
 }

11-11: Consider caching the result for better performance

The file system check is performed each time the method is called. If this method is frequently called during application startup or runtime, it could lead to unnecessary file system operations.

 package greencity.config.dotenv;

 import greencity.constant.AppConstant;

 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Paths;

 public class DotEnvConditionChecker {
+    private static Boolean cachedResult = null;
+    
     public static boolean isEnabled() {
-        return Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + AppConstant.DOTENV_FILENAME));
+        if (cachedResult == null) {
+            cachedResult = Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + AppConstant.DOTENV_FILENAME));
+        }
+        return cachedResult;
     }
 }
service/src/main/java/greencity/config/dotenv/DotenvConfig.java (1)

27-35: Consider consistent method visibility

The fallbackDotenv() method is public while dotenv() has default (package-private) visibility. For consistency, consider making both methods public or package-private.

-    Dotenv dotenv() {
+    public Dotenv dotenv() {
         try {
             return Dotenv.configure()
                 .filename(AppConstant.DOTENV_FILENAME)
                 .load();
         } catch (DotenvException ignored) {
             throw new FunctionalityNotAvailableException(ErrorMessage.FUNCTIONALITY_NOT_AVAILABLE);
         }
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e180da and 484f0d0.

📒 Files selected for processing (2)
  • service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java (1 hunks)
  • service/src/main/java/greencity/config/dotenv/DotenvConfig.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (4)
service/src/main/java/greencity/config/dotenv/DotenvConfig.java (4)

1-1: Good organization by moving to a dedicated package

Moving the DotenvConfig to a dedicated package improves code organization and makes the code more maintainable. This is a positive change.


19-22: Appropriate fallback bean configuration

The fallback bean is correctly configured with @ConditionalOnMissingBean to ensure it's only created when no other Dotenv bean is available. This provides a good default behavior while allowing for customization.


24-27: Well-structured primary bean configuration with conditional creation

The changes to the dotenv() bean are well implemented:

  1. Using @ConditionalOnExpression with the DotEnvConditionChecker is a clean approach
  2. Adding @Primary ensures this bean is preferred when available
  3. The SpEL expression is correctly formed to call the static method

This approach of conditionally creating the bean based on file existence aligns perfectly with the PR objectives.


25-25:

Details

✅ Verification successful

Update expression if DotEnvConditionChecker is changed to a component

If you implement the suggested change to make DotEnvConditionChecker a component rather than using a static method, you'll need to update this SpEL expression.

If you decide to make DotEnvConditionChecker a component, you'll need to update the SpEL expression. Here's how you could verify the current usage:


🏁 Script executed:

#!/bin/bash
# Find all usages of DotEnvConditionChecker in the codebase
rg "DotEnvConditionChecker" --type java

Length of output: 312


Clarification on Static vs. Bean Usage for DotEnvConditionChecker

The verification confirms that the code still accesses DotEnvConditionChecker via its static method:

@ConditionalOnExpression("#{T(greencity.config.dotenv.DotEnvConditionChecker).isEnabled()}")

At this time, no changes are needed because DotEnvConditionChecker is not yet implemented as a component. However, if you refactor it into a Spring component in the future, please update the SpEL expression accordingly. For example, once converted, you might use:

@ConditionalOnExpression("#{dotEnvConditionChecker.isEnabled()}")

This adjustment will ensure that Spring correctly injects and references the bean instead of calling a static method.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java (1)

11-21: Consider adding logging and improving path construction.

The implementation is clear and efficient with the caching strategy, but there are a few potential improvements:

  1. Add logging for the caught exception to aid debugging
  2. Use Paths.get() with multiple arguments instead of string concatenation for more robust path construction
  3. Add Javadoc comments to explain the purpose and behavior of this method

Here's a suggested improvement:

 public static boolean isEnabled() {
     if (cachedValue == null) {
         try {
-            cachedValue = Files
-                .exists(Paths.get(System.getProperty("user.dir") + File.separator + AppConstant.DOTENV_FILENAME));
+            cachedValue = Files.exists(Paths.get(System.getProperty("user.dir"), AppConstant.DOTENV_FILENAME));
         } catch (SecurityException e) {
+            // Log the exception - consider adding a logger
             cachedValue = false;
         }
     }
     return cachedValue;
 }
service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java (2)

44-86: Consider standardizing test method naming conventions.

The test method names are clear but inconsistent - some use the "Test" suffix and others don't. For better readability, consider adopting a consistent naming convention throughout the test class.

For example, either:

- public void checkIsEnabledReturnsTrueIfPathIsValid() {
+ public void checkIsEnabledReturnsTrueIfPathIsValidTest() {

Or:

- public void checkIsEnabledReturnsFalseIfPathNotExistsTest() {
+ public void checkIsEnabledReturnsFalseIfPathNotExists() {

44-86: Consider removing unnecessary public modifiers from test methods.

JUnit test methods don't need to be declared as public since JUnit 5. For cleaner code, you can remove these modifiers.

- @Test
- public void checkIsEnabledReturnsTrueIfPathIsValid() {
+ @Test
+ void checkIsEnabledReturnsTrueIfPathIsValid() {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ba65d6 and fe17f74.

📒 Files selected for processing (2)
  • service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java (1 hunks)
  • service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java (1 hunks)
🔇 Additional comments (7)
service/src/main/java/greencity/config/dotenv/DotEnvConditionChecker.java (1)

1-7: The package structure and imports look appropriate.

The new package greencity.config.dotenv is a good organization choice for dot-env related functionality, and the imports cover the necessary file operations classes.

service/src/test/java/greencity/utils/dotenv/DotEnvConditionCheckerTest.java (6)

1-20: Package structure and imports are well organized.

The imports cover all necessary classes for JUnit testing and Mockito mocking. Good job separating the test package structure from the implementation package.


21-24: Static mock fields are appropriately defined.

Using static mocked instances of Paths and Files is a good approach for testing static methods.


25-42: Test setup and cleanup are well implemented.

The use of reflection to reset the cachedValue field before each test ensures test isolation, which is excellent practice. The proper initialization and closing of mocked static instances in @BeforeAll and @AfterAll methods prevent memory leaks.


44-55: The positive path test is comprehensive.

This test thoroughly verifies that isEnabled() returns true when the file exists and ensures the methods are invoked exactly once.


57-67: The negative path test is well structured.

Good job verifying both the return value and the method invocation counts when the file doesn't exist.


69-76: Security exception handling test is properly implemented.

The test correctly verifies that isEnabled() returns false when a SecurityException is thrown and that Files.exists() is not called in this scenario.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 75%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants