diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 9c2ebd9..f064064 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -9,7 +9,7 @@ name: Java CI with Gradle
 
 on:
   push:
-    branches: [ "main" ]
+    branches: [ "main", "release/**", "feature/**" ]
   pull_request:
     branches: [ "main" ]
 
diff --git a/README.md b/README.md
index 33faaac..b12508f 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,8 @@ plugins {
     id("io.gofannon.cots-report") version ("0.1.0-SNAPSHOT")
 }
 ```
+
+
 ### Extension usage
 The plugin provides the `cotsReport` extension.
 This extension contains 3 properties:
@@ -49,7 +51,10 @@ This extension contains 3 properties:
 * **configurations** which contains the list of the configurations to parse. This property is optional. By default, the configuration is `runtimeClasspath`.
 * **ignorableGroupIds** which contains the list of the groups to ignore. This property is optional. By default, there is no ignorable group.
 
-Example:
+
+### Examples:
+
+__Groovy__
 ```groovy
 cotsReporting {
     reportFile = layout.buildDirectory.file("my-report.txt")
@@ -58,8 +63,19 @@ cotsReporting {
 }
 ```
 
+__Kotlin__
+```kotlin
+cotsReporting {
+    reportFile = layout.buildDirectory.file("sample.txt")
+    configurations.set(listOf("runtimeClasspath","testRuntimeClasspath"))
+    ignorableGroupIds.set(listOf("commons-io", "com.fasterxml.jackson.module", "jackson-module-kotlin"))
+}
+```
+
+
 ## Run
 To run the plugin, just execute the task 
+
 ```shell
 gradle :cotsReport
 ```
diff --git a/build.gradle.kts b/build.gradle.kts
index eae8ae3..c129718 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -34,6 +34,7 @@ dependencies {
     compileOnly("com.google.code.findbugs:jsr305:3.0.2")
 
     testImplementation("org.codehaus.groovy:groovy:3.0.21")
+    //testImplementation("commons-io:commons-io:2.16.0")
 
     testImplementation(platform("org.junit:junit-bom:5.10.1"))
     testImplementation("org.junit.jupiter:junit-jupiter")
diff --git a/gradle.properties b/gradle.properties
index c39bfa4..23ae36a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,2 @@
 kotlin.code.style=official
-version=1.0.0-SNAPSHOT
\ No newline at end of file
+version=1.0.0
\ No newline at end of file
diff --git a/src/main/java/io/gofannon/gradle/cots/report/CotsReportGenerationTask.java b/src/main/java/io/gofannon/gradle/cots/report/CotsReportGenerationTask.java
index 8ec2980..129ce43 100644
--- a/src/main/java/io/gofannon/gradle/cots/report/CotsReportGenerationTask.java
+++ b/src/main/java/io/gofannon/gradle/cots/report/CotsReportGenerationTask.java
@@ -45,7 +45,8 @@ public void initialize(CotsReportExtension extension) {
     private void initializeReportRenderer(CotsReportExtension extension) {
         CotsContext context = createContext(extension);
         DependencyCollector dependencyCollector = new DependencyCollector(context);
-        DependencyReportRenderer reportRenderer = new CotsReportRenderer(dependencyCollector);
+        ReportFormatter formatter = new TextReportFormatter();
+        DependencyReportRenderer reportRenderer = new CotsReportRenderer(dependencyCollector, formatter);
         setRenderer(reportRenderer);
     }
 
diff --git a/src/main/java/io/gofannon/gradle/cots/report/CotsReportRenderer.java b/src/main/java/io/gofannon/gradle/cots/report/CotsReportRenderer.java
index 60f32f7..23a79e3 100644
--- a/src/main/java/io/gofannon/gradle/cots/report/CotsReportRenderer.java
+++ b/src/main/java/io/gofannon/gradle/cots/report/CotsReportRenderer.java
@@ -30,21 +30,19 @@
 
 @NonNullApi
 public class CotsReportRenderer extends TextReportRenderer implements DependencyReportRenderer {
-
+    private final ReportFormatter formatter;
     private final DependencyCollector dependencyCollector;
-
     private DependencyGraphsParser dependencyGraphParser;
 
-    public CotsReportRenderer(DependencyCollector dependencyCollector) {
+    public CotsReportRenderer(DependencyCollector dependencyCollector, ReportFormatter formatter) {
         this.dependencyCollector = dependencyCollector;
+        this.formatter = formatter;
     }
 
     @Override
     public void startProject(ProjectDetails project) {
-        getTextOutput().println("---------------------------------");
-        getTextOutput().println("--- " + project.getDisplayName());
-        getTextOutput().println("---------------------------------");
-
+        this.formatter.setOutput(getTextOutput());
+        formatter.printProjectHeader(project);
         dependencyGraphParser = new DependencyGraphsParser(dependencyCollector);
     }
 
@@ -88,18 +86,7 @@ public void parseRenderableDependency(RenderableDependency root) {
 
     @Override
     public void complete() {
-        getTextOutput().println("--- COTS configurations");
-        for (var configurationName : dependencyCollector.getConfigurationList()) {
-            getTextOutput().println(configurationName);
-        }
-
-        getTextOutput().println();
-
-        getTextOutput().println("--- COTS dependencies");
-        List<String> dependencyList = dependencyCollector.getDependencyIdList();
-        dependencyList.sort(String::compareTo);
-        for (var dependencyId : dependencyList) {
-            getTextOutput().println(dependencyId);
-        }
+        formatter.printConfigurations(dependencyCollector.getConfigurationList());
+        formatter.printDependencies(dependencyCollector.getDependencyIdList());
     }
 }
\ No newline at end of file
diff --git a/src/main/java/io/gofannon/gradle/cots/report/DependencyCollector.java b/src/main/java/io/gofannon/gradle/cots/report/DependencyCollector.java
index 03350fa..e696db6 100644
--- a/src/main/java/io/gofannon/gradle/cots/report/DependencyCollector.java
+++ b/src/main/java/io/gofannon/gradle/cots/report/DependencyCollector.java
@@ -32,8 +32,8 @@ public class DependencyCollector implements DependencyVisitor {
 
     private final DependencyCollectorConfiguration configuration;
 
-    private final SortedSet<String> dependencyIdSet  = new TreeSet<>();
-    private final SortedSet<String> configurationNameSet  = new TreeSet<>();
+    private final SortedSet<String> dependencyIdSet = new TreeSet<>();
+    private final SortedSet<String> configurationNameSet = new TreeSet<>();
 
 
     /**
@@ -42,11 +42,10 @@ public class DependencyCollector implements DependencyVisitor {
      * @param configuration all information to select the dependencies to collect
      */
     public DependencyCollector(DependencyCollectorConfiguration configuration) {
-this.configuration = configuration;
+        this.configuration = configuration;
     }
 
 
-
     /**
      * Visit a Gradle dependency (aka JAR)
      *
diff --git a/src/main/java/io/gofannon/gradle/cots/report/ReportFormatter.java b/src/main/java/io/gofannon/gradle/cots/report/ReportFormatter.java
new file mode 100644
index 0000000..967e63d
--- /dev/null
+++ b/src/main/java/io/gofannon/gradle/cots/report/ReportFormatter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gofannon.gradle.cots.report;
+
+import org.gradle.api.NonNullApi;
+import org.gradle.api.tasks.diagnostics.internal.ProjectDetails;
+import org.gradle.internal.logging.text.StyledTextOutput;
+
+import java.util.List;
+
+/**
+ * Formatter for dependency report
+ */
+@NonNullApi
+public interface ReportFormatter {
+
+    /**
+     * Inject the  console output
+     *
+     * @param output the console output
+     */
+    void setOutput(StyledTextOutput output);
+
+    /**
+     * Print the header of the project
+     *
+     * @param project the project to print
+     */
+    void printProjectHeader(ProjectDetails project);
+
+    /**
+     * Print the configurations in the project
+     *
+     * @param configurationNames the names of the configurations
+     */
+    void printConfigurations(List<String> configurationNames);
+
+    /**
+     * Print the dependencies in the project
+     *
+     * @param dependencyIdList the list of the dependency identifiers
+     */
+    void printDependencies(List<String> dependencyIdList);
+}
diff --git a/src/main/java/io/gofannon/gradle/cots/report/TextReportFormatter.java b/src/main/java/io/gofannon/gradle/cots/report/TextReportFormatter.java
new file mode 100644
index 0000000..d01c301
--- /dev/null
+++ b/src/main/java/io/gofannon/gradle/cots/report/TextReportFormatter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.gofannon.gradle.cots.report;
+
+import org.gradle.api.NonNullApi;
+import org.gradle.api.tasks.diagnostics.internal.ProjectDetails;
+import org.gradle.internal.logging.text.StyledTextOutput;
+
+import java.util.List;
+
+/**
+ * Dependency report formatter that generates report in text format
+ */
+@NonNullApi
+public class TextReportFormatter implements ReportFormatter {
+
+    private StyledTextOutput output;
+
+    @Override
+    public void setOutput(StyledTextOutput output) {
+        this.output = output;
+    }
+
+    @Override
+    public void printProjectHeader(ProjectDetails project) {
+        output.println("---------------------------------")
+                .println("--- " + project.getDisplayName())
+                .println("---------------------------------");
+    }
+
+    @Override
+    public void printConfigurations(List<String> configurationNames) {
+        output.println("--- COTS configurations");
+        configurationNames.stream()
+                .sorted(String::compareTo)
+                .forEach(output::println);
+        output.println();
+    }
+
+
+    @Override
+    public void printDependencies(List<String> dependencyIdList) {
+        output.println("--- COTS dependencies");
+        dependencyIdList.stream()
+                .sorted(String::compareTo)
+                .forEach(output::println);
+    }
+}
diff --git a/src/test/groovy/io/gofannon/gradle/cots/report/BuildLogicFunctionalTest.groovy b/src/test/groovy/io/gofannon/gradle/cots/report/BuildLogicFunctionalTest.groovy
new file mode 100644
index 0000000..883a560
--- /dev/null
+++ b/src/test/groovy/io/gofannon/gradle/cots/report/BuildLogicFunctionalTest.groovy
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.gofannon.gradle.cots.report
+
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import spock.lang.Specification
+import spock.lang.TempDir
+
+import static io.gofannon.gradle.cots.report.CotsReportHelper.*
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
+
+class BuildLogicFunctionalTest extends Specification {
+
+    @TempDir
+    File testProjectDir
+    File settingsFile
+    File buildFile
+    File defaultReportFile
+    BuildResult buildResult
+
+    private static String baseBuildGradle = """
+            plugins {
+                id 'java'
+                id 'io.gofannon.cots-report' version("1.0.0-SNAPSHOT")
+            }
+
+            dependencies {
+                implementation "org.junit.platform:junit-platform-commons:1.10.2"
+                testImplementation("commons-io:commons-io:2.16.0")
+            }
+            
+            repositories {
+                mavenCentral()
+            }
+        """
+
+    def setup() {
+        settingsFile = new File(testProjectDir, 'settings.gradle')
+        buildFile = new File(testProjectDir, 'build.gradle')
+        defaultReportFile = new File(testProjectDir, "build/reports/project/cots-report.txt")
+    }
+
+    def "can execute cotsReport task with no cotsReporting extension"() {
+        given:
+        buildFile << baseBuildGradle
+        settingsFile << ""
+
+
+        when:
+        runGradleCotsReportTask()
+        def reportFile = defaultReportFile
+
+
+        then:
+        buildResult.task(":cotsReport").outcome == SUCCESS
+        buildResult.output.contains("See the report at: " + formatToClickableUrl(reportFile))
+        reportFile.exists()
+        extractConfigurations(reportFile) == List.of("runtimeClasspath")
+        extractDependencies(reportFile) == List.of("org.junit.platform:junit-platform-commons:1.10.2", "org.junit:junit-bom:5.10.2")
+    }
+
+    private def runGradleCotsReportTask() {
+        buildResult= GradleRunner.create()
+                .withGradleVersion("8.4")
+                .withProjectDir(testProjectDir)
+                .withPluginClasspath()
+                .withArguments('cotsReport')
+                .build()
+    }
+
+
+    def "can execute cotsReport task with empty cotsReporting extension"() {
+        given:
+        buildFile << baseBuildGradle+"""
+            cotsReporting {}
+            """
+        settingsFile << ""
+
+        when:
+        runGradleCotsReportTask()
+        def reportFile = defaultReportFile
+
+
+        then:
+        buildResult.task(":cotsReport").outcome == SUCCESS
+        buildResult.output.contains("See the report at: " + formatToClickableUrl(reportFile))
+        reportFile.exists()
+        extractConfigurations(reportFile) == List.of("runtimeClasspath")
+        extractDependencies(reportFile) == List.of("org.junit.platform:junit-platform-commons:1.10.2", "org.junit:junit-bom:5.10.2")
+    }
+
+
+
+
+    def "can execute cotsReport task with reportFile property set"() {
+        given:
+        buildFile << baseBuildGradle+"""
+            cotsReporting {
+                reportFile = layout.buildDirectory.file("sample.txt")
+            }
+            """
+        settingsFile << ""
+
+        when:
+        runGradleCotsReportTask()
+        def reportFile = new File(testProjectDir, "build/sample.txt")
+
+
+        then:
+        buildResult.task(":cotsReport").outcome == SUCCESS
+        buildResult.output.contains("See the report at: " + formatToClickableUrl(reportFile))
+        reportFile.exists()
+        extractConfigurations(reportFile) == List.of("runtimeClasspath")
+        extractDependencies(reportFile) == List.of("org.junit.platform:junit-platform-commons:1.10.2", "org.junit:junit-bom:5.10.2")
+    }
+
+
+    def "can execute cotsReport task with ignorableGroupIds property set"() {
+        given:
+        buildFile << baseBuildGradle+"""
+            cotsReporting {
+                ignorableGroupIds = ["org.junit"]
+            }
+            """
+        settingsFile << ""
+
+        when:
+        runGradleCotsReportTask()
+        def reportFile = defaultReportFile
+
+
+        then:
+        buildResult.task(":cotsReport").outcome == SUCCESS
+        buildResult.output.contains("See the report at: " + formatToClickableUrl(reportFile))
+        reportFile.exists()
+        extractConfigurations(reportFile) == List.of("runtimeClasspath")
+        extractDependencies(reportFile) == List.of("org.junit.platform:junit-platform-commons:1.10.2")
+    }
+
+
+    def "can execute cotsReport task with configurations property set"() {
+        given:
+        buildFile << baseBuildGradle+"""
+            cotsReporting {
+                configurations = ["testRuntimeClasspath"]
+            }
+            """
+        settingsFile << ""
+
+        when:
+        runGradleCotsReportTask()
+        def reportFile = defaultReportFile
+
+
+        then:
+        buildResult.task(":cotsReport").outcome == SUCCESS
+        buildResult.output.contains("See the report at: " + formatToClickableUrl(reportFile))
+        reportFile.exists()
+        extractConfigurations(reportFile) == List.of("testRuntimeClasspath")
+        extractDependencies(reportFile) == List.of("commons-io:commons-io:2.16.0","org.junit.platform:junit-platform-commons:1.10.2", "org.junit:junit-bom:5.10.2")
+    }
+
+}
diff --git a/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportGenerationTaskTest.groovy b/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportGenerationTaskTest.groovy
deleted file mode 100644
index 5764890..0000000
--- a/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportGenerationTaskTest.groovy
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.gofannon.gradle.cots.report
-
-import spock.lang.Specification
-//import org.gradle.test.fixtures.AbstractProjectBuilderSpec
-//import org.gradle.util.TestUtil
-import org.gradle.testkit.runner.GradleRunner
-
-class CotsReportGenerationTaskTest /*extends AbstractProjectBuilderSpec*/ {
-
-}
diff --git a/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportHelper.groovy b/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportHelper.groovy
new file mode 100644
index 0000000..c491e18
--- /dev/null
+++ b/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportHelper.groovy
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.gofannon.gradle.cots.report
+
+class CotsReportHelper {
+
+    static def extractConfigurations(File reportFile) {
+        return extractSectionElements(reportFile, "--- COTS configurations")
+    }
+
+    private static def extractSectionElements(File reportFile, String sectionTitle) {
+        def inside = false
+        def configurationList = new ArrayList<String>()
+        for (def line : reportFile.text.lines()) {
+            if (line == sectionTitle) {
+                inside = true
+            } else if (inside) {
+                if (line.isEmpty())
+                    break
+                configurationList.add(line)
+            }
+        }
+        return configurationList
+    }
+
+    static def extractDependencies(File reportFile) {
+        return extractSectionElements(reportFile, "--- COTS dependencies")
+    }
+
+
+    static def formatToClickableUrl(File file) {
+        def url = file.toURI().toString()
+        if (url.startsWith("file:///"))
+            return url
+        if (url.startsWith("file:/"))
+            return url.replace("file:/", "file:///")
+        return "file:///" + url
+    }
+
+}
diff --git a/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportPluginTest.groovy b/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportPluginTest.groovy
new file mode 100644
index 0000000..5e2f6e7
--- /dev/null
+++ b/src/test/groovy/io/gofannon/gradle/cots/report/CotsReportPluginTest.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.gofannon.gradle.cots.report
+
+import org.gradle.testfixtures.ProjectBuilder
+import spock.lang.Specification
+
+class CotsReportPluginTest extends Specification {
+
+    def "plugin shall be accessible"() {
+        given:
+        def project = ProjectBuilder.builder().build()
+        project.getPluginManager().apply("io.gofannon.cots-report")
+
+
+        expect:
+        project.getPluginManager().hasPlugin("io.gofannon.cots-report")
+        project.getTasks().named("cotsReport") != null
+    }
+
+}