Compare commits

...

74 commits
0.9.1 ... main

Author SHA1 Message Date
ea10fd012f
Disable cleanPath() for testing 2025-03-24 19:01:12 -07:00
69a9eac414
Add baseline file for testing 2025-03-24 17:36:30 -07:00
5a2824507f
Removed paths quoting 2025-03-24 16:12:15 -07:00
3e350e617a
Bump detekt extension to version 0.9.10-SNAPSHOT 2025-03-24 16:11:11 -07:00
432e5ffed1
Enable extension logging in examples 2025-03-24 16:09:45 -07:00
e6d5c6c38f
Quote and clean path in the process command list 2025-03-24 10:06:41 -07:00
7d5b50641c
Add OS matrix to test the project and examples on Ubuntu, Windows and macOS 2025-03-24 01:44:39 -07:00
30f92d1262
Bump Kotlin extension to version 1.1.0-SNAPSHOT 2025-03-24 01:39:53 -07:00
8d4643d99a
Bump Kotlin to version 2.1.20 2025-03-24 01:38:50 -07:00
0efd5ab2fe
JDK 24 2025-03-18 23:34:19 -07:00
3df50c2e79
Add generic installation instructions 2025-03-18 13:07:29 -07:00
012cd14067
Bump PMD extension to version 1.2.1 2025-03-18 13:06:22 -07:00
e39302bf8b
Bump JUnit to version 5.12.1 2025-03-18 13:06:07 -07:00
41d6667dca
Bump bld to version 2.2.1 2025-02-24 22:48:05 -08:00
7386332361
Version 0.9.9 2025-02-23 16:32:20 -08:00
95971222f9
Bump Detekt to version 1.23.8 2025-02-23 16:29:33 -08:00
ae53af2ba6
Bump PMD extension to version 1.2.0 2025-02-23 15:44:28 -08:00
7ad511a40c
Bump JUnit to version 5.12.0 2025-02-23 15:44:28 -08:00
1115acaad4
Update pages actions to the latest versions 2025-02-23 15:44:27 -08:00
d6f424972a
Version 0.9.8 2025-01-14 12:09:51 -08:00
99691fb2e9
Fixed BaseProjectBlueprint init in tests 2025-01-14 00:08:10 -08:00
48952f505f
Updated copyright for 2025 2025-01-14 00:05:55 -08:00
93d963398b
Bumped bld to version 2.2.0 2025-01-14 00:04:44 -08:00
1bef03ec79
Bumped AssertJ to version 3.27.2 2025-01-14 00:04:14 -08:00
d1f4a614fe
Bumped Kotlin extension to version 1.0.4 2025-01-14 00:03:46 -08:00
33774b8a93
Updated extensions
Bumped Kotlin extension to version 1.0.3
Bumped PMD extension to version 1.1.9
2024-12-28 17:46:39 -08:00
cbe95f7cc2
Bumped Kotlin to version 2.1.0 2024-12-28 17:45:36 -08:00
c993a3ab14
Bumped AssertJ to version 3.27.0 2024-12-28 17:44:36 -08:00
5b6181825d
Bumped JUnit to version 5.11.4 2024-12-28 17:43:40 -08:00
e04f46287b
Updated dependencies
Bumped JUnit version to 5.11.3
Bumped PMD extension version to 1.1.7
Bumped JDK to version 23 (GitHub CI Workflow)
Bumped Kotlin to version 2.0.21
Bumped Kotlin extension to version 1.0.2
2024-10-27 17:03:26 -07:00
a1eb4cea1d
Bumped bld to version 1.23.7 2024-09-08 18:35:57 -07:00
21bd30166d
Version 0.9.6 2024-08-30 16:59:15 -07:00
e9f3079911
More API cleanups 2024-08-30 16:59:02 -07:00
158167bebd
Bumped bld to version 2.1.0 2024-08-30 16:55:52 -07:00
324fc48c40
Cleaned up API to match bld operations and options APIs 2024-08-28 00:12:55 -07:00
c6307577aa
Bumped Kotlin to version 2.0.20 2024-08-28 00:12:35 -07:00
0a989544ae
Bumped JUnit to version 5.11.0 2024-08-28 00:12:18 -07:00
cf385a58cb
Bumped Kotlin to version 2.0.10 2024-08-09 17:59:02 -07:00
05ac3a44e8
Version 0.9.5 2024-07-29 16:14:29 -07:00
e4ccacab60
Bumped bld to version 2.0.1 2024-07-29 16:05:08 -07:00
8b02e1e45a
Ensured exit status is set on failure 2024-07-22 16:43:44 -07:00
b26240df76
Bumped bld to version 2.0.0-SHAPSHOT 2024-07-22 16:27:13 -07:00
b2574279eb
Use SNAPSHOT in examples 2024-06-22 17:36:25 -07:00
a6be88bf54
Added includes and excludes collection
Changed Collection<String> to Collection<File> whenever applicable
2024-06-22 17:28:55 -07:00
29255aae21
Fixed copyright template 2024-06-22 17:27:14 -07:00
093a32cfdd
Bumped extensions dependencies
Exec to version 1.0.1
PMD to version 1.1.0
2024-06-22 17:26:07 -07:00
4b101bb183
Moved Report and ReportID to their own sub-package 2024-06-22 17:23:46 -07:00
be15297cc5
Execute cliargs script before running tests 2024-05-28 13:54:33 -07:00
7413565d87
Read parameters from resource file 2024-05-27 20:55:00 -07:00
1e62bc3fba
Added script to list parameters 2024-05-27 16:12:39 -07:00
32e95b2efa
Bumped Kotlin extension to version 0.9.8 2024-05-26 22:25:58 -07:00
6fa52100ec
Added test for all parameters 2024-05-26 18:58:12 -07:00
61c200ee54
Bumped assertj-core to version 3.26.0 2024-05-26 17:39:06 -07:00
833eddf28c
Bumped Kotlin to version 2.0.0 2024-05-23 22:05:56 -07:00
0a716260ac
Normalized execution logging messages 2024-05-23 21:52:42 -07:00
154359e0cd
Version 0.9.4 2024-05-12 17:47:06 -07:00
6946a3c26d
Log if baseline generation was successful 2024-05-11 15:09:16 -07:00
251425c625
Updated bld badge 2024-05-09 21:02:32 -07:00
1523e0a2b7
Bumped Kotlin to version 1.9.24 2024-05-09 21:02:09 -07:00
6d518a8b64
Bumped PMD extension to version 0.9.9 2024-05-09 21:01:33 -07:00
4db7553ca1
Bumped bld to version 1.9.1 2024-05-09 21:01:01 -07:00
a4d443d26b
Bumped Detekt extension to 0.9.4-SNAPSHOT 2024-04-17 22:41:34 -07:00
5f33e4263c
Bumped to version 0.9.4-SNAPSHOT 2024-04-17 22:37:49 -07:00
40dd2ce116
Log if execution was successful 2024-04-12 00:13:37 -07:00
e6104f1fed
Bumped workflows actions to latest versions 2024-04-12 00:12:40 -07:00
dddcad61b4
Added support for Detekt version 1.23.6 2024-03-25 11:54:09 -07:00
3483103c24
Bumped Kotlin version to 1.9.23 2024-03-21 13:40:00 -07:00
062dfbfe39
Added JDK 22 to CI 2024-03-21 13:39:04 -07:00
ba1518b045
Bumped to bld 1.9.0 2024-03-21 00:29:24 -07:00
6b65a32bd3
Bumped JUnit versions 2024-03-21 00:29:23 -07:00
91185dafc1
Improved Visual Studio Code support 2024-03-21 00:29:23 -07:00
10eed8921a
Version 0.9.1 2024-03-21 00:29:23 -07:00
da387d714b
Bumped detekt to version 1.23.5 2024-03-21 00:29:17 -07:00
532ca02f39
Added script to compare CLI arguments 2024-03-21 00:29:10 -07:00
36 changed files with 1042 additions and 307 deletions

View file

@ -4,35 +4,36 @@ on: [ push, pull_request, workflow_dispatch ]
jobs:
build-bld-project:
runs-on: ubuntu-latest
strategy:
matrix:
java-version: [ 17, 20 ]
java-version: [ 17, 21, 24 ]
kotlin-version: [ 1.9.25, 2.0.21, 2.1.20 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
distribution: "zulu"
java-version: ${{ matrix.java-version }}
- name: Grant execute permission for bld
run: chmod +x bld
- name: Download the dependencies
- name: Download dependencies [examples]
working-directory: examples
run: ./bld download
- name: Download the examples dependencies
run: |
cd examples
chmod +x bld
./bld download
- name: Run Detekt [examples]
working-directory: examples
run: ./bld compile test-ci
- name: Run tests with bld
run: ./bld compile test
- name: Download dependencies
run: ./bld download
- name: Run tests
run: ./bld compile test

View file

@ -30,14 +30,14 @@ jobs:
steps:
- name: Checkout source repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
distribution: "zulu"
java-version: 17
- name: Build Javadocs
@ -47,11 +47,11 @@ jobs:
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v3
with:
# Upload generated Javadocs repository
path: 'build/javadoc/'
path: "build/javadoc/"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v4

6
.idea/bld.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BldConfiguration">
<events />
</component>
</project>

View file

@ -1,6 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright 2023-Copyright &amp;#36;today.yearamp;#36;today.year the original author or authors.&#10; &#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; https://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="notice" value="Copyright 2023-&amp;#36;today.year the original author or authors.&#10; &#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; https://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="Apache License" />
</copyright>
</component>
</component>

13
.idea/icon.svg generated Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 179 108" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-210.511,-96.3382)">
<g transform="matrix(1,0,0,1,-23.3386,-649.816)">
<g transform="matrix(0.221288,0,0,0.24,73.9536,390.254)">
<path d="M722.568,1482.92L722.568,1921.1L808.968,1921.1L808.968,1888.7C822.168,1907.9 846.168,1930.1 893.568,1930.1C933.168,1930.1 961.968,1917.5 985.368,1893.5C1012.97,1865.9 1027.37,1827.5 1027.37,1786.1C1027.37,1741.7 1011.17,1705.1 985.368,1680.5C961.968,1658.3 928.968,1644.5 892.368,1644.5C862.968,1644.5 830.568,1654.1 808.968,1683.5L808.968,1482.92L722.568,1482.92ZM871.368,1718.9C888.768,1718.9 903.768,1723.7 917.568,1736.9C930.168,1748.9 938.568,1766.3 938.568,1787.9C938.568,1807.7 930.168,1825.1 917.568,1837.1C904.368,1849.7 887.568,1855.7 872.568,1855.7C856.368,1855.7 837.168,1849.1 823.368,1835.9C813.168,1826.3 803.568,1810.1 803.568,1787.9C803.568,1765.1 812.568,1749.5 822.768,1738.7C836.568,1724.3 852.768,1718.9 871.368,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
<rect x="1083.77" y="1482.92" width="86.4" height="438.182" style="fill:rgb(250,144,82);fill-rule:nonzero;"/>
<path d="M1531.37,1482.92L1444.97,1482.92L1444.97,1683.5C1423.37,1654.1 1390.97,1644.5 1361.57,1644.5C1324.97,1644.5 1291.97,1658.3 1268.57,1680.5C1242.77,1705.1 1226.57,1741.7 1226.57,1786.1C1226.57,1827.5 1240.97,1865.9 1268.57,1893.5C1291.97,1917.5 1320.77,1930.1 1360.37,1930.1C1407.77,1930.1 1431.77,1907.9 1444.97,1888.7L1444.97,1921.1L1531.37,1921.1L1531.37,1482.92ZM1382.57,1718.9C1401.17,1718.9 1417.37,1724.3 1431.17,1738.7C1441.37,1749.5 1450.37,1765.1 1450.37,1787.9C1450.37,1810.1 1440.77,1826.3 1430.57,1835.9C1416.77,1849.1 1397.57,1855.7 1381.37,1855.7C1366.37,1855.7 1349.57,1849.7 1336.37,1837.1C1323.77,1825.1 1315.37,1807.7 1315.37,1787.9C1315.37,1766.3 1323.77,1748.9 1336.37,1736.9C1350.17,1723.7 1365.17,1718.9 1382.57,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -2,12 +2,12 @@
<library name="bld">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.8.0.jar!/" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.8.0-sources.jar!/" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
</SOURCES>
<excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -7,7 +7,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" />
</library>
</component>

14
.idea/misc.xml generated
View file

@ -3,20 +3,6 @@
<component name="EntryPointsManager">
<pattern value="rife.bld.extension.DetektOperationBuild" method="pmd" />
</component>
<component name="PDMPlugin">
<option name="customRuleSets">
<list>
<option value="K:\java\semver\config\pmd.xml" />
<option value="$PROJECT_DIR$/../bld-generated-version/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-pitest/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-jacoco-report/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-checkstyle/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-exec/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-testng/config/pmd.xml" />
</list>
</option>
<option name="skipTestSources" value="false" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build" />
</component>

9
.vscode/launch.json vendored
View file

@ -5,7 +5,14 @@
"type": "java",
"name": "Run Tests",
"request": "launch",
"mainClass": "rife.bld.extension.DetektOperationTest"
"mainClass": "org.junit.platform.console.ConsoleLauncher",
"args": [
"--details=verbose",
"--scan-classpath",
"--disable-banner",
"--disable-ansi-colors",
"--exclude-engine=junit-platform-suite",
"--exclude-engine=junit-vintage"]
}
]
}

10
.vscode/settings.json vendored
View file

@ -3,13 +3,13 @@
"src/main/java",
"src/main/resources",
"src/test/java",
"src/bld/java"
"src/test/resources",
"src/bld/java",
"src/bld/resources"
],
"java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [
"${HOME}/.bld/dist/bld-1.8.0.jar",
"lib/compile/*.jar",
"lib/runtime/*.jar",
"lib/test/*.jar"
"${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/**/*.jar"
]
}

View file

@ -3,12 +3,20 @@
[![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![Release](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/releases/com/uwyn/rife2/bld-detekt/maven-metadata.xml?color=blue)](https://repo.rife2.com/#/releases/com/uwyn/rife2/bld-detekt)
[![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-detekt/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-detekt)
[![GitHub CI](https://github.com/rife2/bld-detekt/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-detekt/actions/workflows/bld.yml)
To install, please refer to the [extensions documentation](https://github.com/rife2/bld/wiki/Extensions).
To install the latest version, add the following to the `lib/bld/bld-wrapper.properties` file:
```properties
bld.extension-detekt=com.uwyn.rife2:bld-detekt
```
For more information, please refer to the [extensions](https://github.com/rife2/bld/wiki/Extensions) documentation.
## Check Source Code with Detekt
To check all Kotlin source code located in the project, add the following to your build file:
```java
@ -45,3 +53,7 @@ public void detektBaseline() throws ExitStatusException, IOException, Interrupte
- [View Examples Project](https://github.com/rife2/bld-detekt/tree/main/examples)
Please check the [DetektOperation documentation](https://rife2.github.io/bld-detekt/rife/bld/extension/DetektOperation.html#method-summary) for all available configuration options.
## Template Project
There is also a [Kotlin Template Project](https://github.com/rife2/kotlin-bld-example) with support for [Dokka](https://github.com/rife2/bld-dokka) and the Detekt extensions.

View file

@ -7,9 +7,9 @@
<!-- BEST PRACTICES -->
<rule ref="category/java/bestpractices.xml">
<exclude name="AvoidPrintStackTrace"/>
<exclude name="JUnit4TestShouldUseTestAnnotation"/>
<exclude name="JUnitTestContainsTooManyAsserts"/>
<exclude name="GuardLogStatement"/>
<exclude name="UnitTestContainsTooManyAsserts"/>
<exclude name="UnitTestShouldUseTestAnnotation"/>
</rule>
<rule ref="category/java/bestpractices.xml/MissingOverride">
@ -19,15 +19,15 @@
</properties>
</rule>
<!-- CODE STYLE -->
<rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/>
<exclude name="ClassNamingConventions"/>
<exclude name="ConfusingTernary"/>
<exclude name="CommentDefaultAccessModifier"/>
<exclude name="ConfusingTernary"/>
<exclude name="FieldNamingConventions"/>
<exclude name="LocalVariableCouldBeFinal"/>
<exclude name="LocalVariableNamingConventions"/>
<exclude name="LongVariable"/>
<exclude name="MethodArgumentCouldBeFinal"/>
<exclude name="OnlyOneReturn"/>
@ -35,8 +35,9 @@
<exclude name="ShortClassName"/>
<exclude name="ShortMethodName"/>
<exclude name="ShortVariable"/>
<exclude name="UselessParentheses"/>
<exclude name="UseExplicitTypes"/>
<exclude name="UseUnderscoresInNumericLiterals"/>
<exclude name="UselessParentheses"/>
</rule>
<rule ref="category/java/codestyle.xml/UnnecessaryImport">
@ -52,8 +53,6 @@
<exclude name="AvoidUncheckedExceptionsInSignatures"/>
<exclude name="CognitiveComplexity"/>
<exclude name="CyclomaticComplexity"/>
<exclude name="ExcessiveClassLength"/>
<exclude name="ExcessiveMethodLength"/>
<exclude name="ExcessiveParameterList"/>
<exclude name="ExcessivePublicCount"/>
<exclude name="GodClass"/>
@ -107,4 +106,4 @@
<!-- SECURITY -->
<rule ref="category/java/security.xml">
</rule>
</ruleset>
</ruleset>

6
examples/.idea/bld.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BldConfiguration">
<events />
</component>
</project>

View file

@ -2,12 +2,12 @@
<library name="bld">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.8.0.jar!/" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.8.0-sources.jar!/" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
</SOURCES>
<excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -7,7 +7,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -5,7 +5,11 @@
"type": "java",
"name": "Run Tests",
"request": "launch",
"mainClass": "com.example.ExampleTest"
"mainClass": "com.example.ExampleBuild",
"args": [
"compile",
"test"
]
}
]
}

View file

@ -3,13 +3,13 @@
"src/main/java",
"src/main/resources",
"src/test/java",
"src/bld/java"
"src/test/resources",
"src/bld/java",
"src/bld/resources"
],
"java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [
"${HOME}/.bld/dist/bld-1.8.0.jar",
"lib/compile/*.jar",
"lib/runtime/*.jar",
"lib/test/*.jar"
"${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/**/*.jar"
]
}

View file

@ -1,4 +1,4 @@
## Compile the Kotlin Example
## Compile the example
```console
./bld compile

Binary file not shown.

View file

@ -1,8 +1,8 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.0
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.downloadLocation=
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.sourceDirectories=
bld.version=1.8.0
bld.version=2.2.1

View file

@ -25,17 +25,20 @@ public class ExampleBuild extends Project {
version = version(0, 1, 0);
javaRelease = 17;
downloadSources = true;
autoDownloadPurge = true;
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES);
final var kotlin = version(1, 9, 22);
final var kotlin = version(2, 1, 20);
scope(compile)
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin));
scope(test)
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1)));
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1)))
.include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 1)));
// Include the Kotlin source directory when creating or publishing sources Java Archives
jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin"));
@ -43,21 +46,21 @@ public class ExampleBuild extends Project {
public static void main(String[] args) {
// Enable detailed logging
// var level = Level.ALL;
// var logger = Logger.getLogger("rife.bld.extension");
// var consoleHandler = new ConsoleHandler();
var level = Level.ALL;
var logger = Logger.getLogger("rife.bld.extension");
var consoleHandler = new ConsoleHandler();
// consoleHandler.setLevel(level);
// logger.addHandler(consoleHandler);
// logger.setLevel(level);
// logger.setUseParentHandlers(false);
consoleHandler.setLevel(level);
logger.addHandler(consoleHandler);
logger.setLevel(level);
logger.setUseParentHandlers(false);
new ExampleBuild().start(args);
}
@BuildCommand(summary = "Compiles the Kotlin project")
@Override
public void compile() throws IOException {
public void compile() throws Exception {
new CompileKotlinOperation()
.fromProject(this)
.execute();
@ -98,4 +101,13 @@ public class ExampleBuild extends Project {
.input("src/test/kotlin")
.execute();
}
}
@BuildCommand(value = "test-ci", summary = "Run detek with a test baseline")
public void testCi() throws ExitStatusException, IOException, InterruptedException {
// Run detek with the test basline (for CI testing)
new DetektOperation()
.fromProject(this)
.baseline("src/test/resources/detekt-baseline.xml")
.execute();
}
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>EmptyIfBlock:Example.kt$Example.Companion${ }</ID>
<ID>MagicNumber:Example.kt$Example$5</ID>
<ID>NewLineAtEndOfFile:ExampleTest.kt$com.example.ExampleTest.kt</ID>
<ID>ThrowingExceptionsWithoutMessageOrCause:Example.kt$Example.Companion$IllegalStateException()</ID>
<ID>UseCheckOrError:Example.kt$Example.Companion$throw IllegalStateException()</ID>
<ID>VariableNaming:Example.kt$Example$// https://detekt.dev/docs/rules/naming#variablenaming val Message: String get() = "Hello World!"</ID>
</CurrentIssues>
</SmellBaseline>

Binary file not shown.

View file

@ -1,7 +1,8 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.extension-pmd=com.uwyn.rife2:bld-pmd:0.9.5
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.downloadLocation=
bld.extension-exec=com.uwyn.rife2:bld-exec:1.0.4
bld.extension-pmd=com.uwyn.rife2:bld-pmd:1.2.1
bld.repositories=MAVEN_CENTRAL,MAVEN_LOCAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.sourceDirectories=
bld.version=1.8.0
bld.version=2.2.1

12
scripts/checkcliargs.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
main=io.gitlab.arturbosch.detekt.cli.Main
new=/tmp/checkcliargs-new
old=/tmp/checkcliargs-old
java -cp "lib/compile/*:examples/lib/bld/*" $main --help >$new
java -cp "examples/lib/bld/*" $main --help >$old
diff $old $new
rm -rf $new $old

8
scripts/cliargs.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
java -cp "lib/compile/*:examples/lib/bld/*" io.gitlab.arturbosch.detekt.cli.Main --help |\
grep "^ --.*" |\
sed -e "s/ //" -e "s/, .*//" -e '/version/d' -e '/help/d' |\
sort |\
sed -e '$s/,//' > "src/test/resources/detekt-args.txt"

View file

@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
@ -23,9 +23,9 @@ import rife.bld.publish.PublishLicense;
import rife.bld.publish.PublishScm;
import java.util.List;
import java.util.Locale;
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
import static rife.bld.dependencies.Repository.RIFE2_RELEASES;
import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.compile;
import static rife.bld.dependencies.Scope.test;
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
@ -34,20 +34,22 @@ public class DetektOperationBuild extends Project {
public DetektOperationBuild() {
pkg = "rife.bld.extension";
name = "DetektOperation";
version = version(0, 9, 0);
version = version(0, 9, 10, "SNAPSHOT");
javaRelease = 17;
downloadSources = true;
autoDownloadPurge = true;
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL, RIFE2_RELEASES, RIFE2_SNAPSHOTS);
scope(compile)
.include(dependency("com.uwyn.rife2", "bld", version(1, 8, 0)))
.include(dependency("io.gitlab.arturbosch.detekt", "detekt-cli", version(1, 23, 4)));
.include(dependency("com.uwyn.rife2", "bld", version(2, 2, 1)))
.include(dependency("io.gitlab.arturbosch.detekt", "detekt-cli", version(1, 23, 8)));
scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1)))
.include(dependency("org.assertj", "assertj-core", version(3, 25, 2)));
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1)))
.include(dependency("org.assertj", "assertj-core", version(3, 27, 3)));
javadocOperation()
.javadocOptions()
.author()
@ -57,28 +59,26 @@ public class DetektOperationBuild extends Project {
publishOperation()
.repository(version.isSnapshot() ? repository("rife2-snapshot") : repository("rife2"))
.repository(repository("github"))
.info()
.groupId("com.uwyn.rife2")
.artifactId("bld-detekt")
.description("bld Detekt Extension")
.url("https://github.com/rife2/bld-detekt")
.developer(
new PublishDeveloper()
.id("ethauvin")
.name("Erik C. Thauvin")
.email("erik@thauvin.net")
.url("https://erik.thauvin.net/")
.developer(new PublishDeveloper()
.id("ethauvin")
.name("Erik C. Thauvin")
.email("erik@thauvin.net")
.url("https://erik.thauvin.net/")
)
.license(
new PublishLicense()
.name("The Apache License, Version 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.txt")
.license(new PublishLicense()
.name("The Apache License, Version 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0.txt")
)
.scm(
new PublishScm()
.connection("scm:git:https://github.com/rife2/bld-detekt.git")
.developerConnection("scm:git:git@github.com:rife2/bld-detekt.git")
.url("https://github.com/rife2/bld-detekt")
.scm(new PublishScm()
.connection("scm:git:https://github.com/rife2/bld-detekt.git")
.developerConnection("scm:git:git@github.com:rife2/bld-detekt.git")
.url("https://github.com/rife2/bld-detekt")
)
.signKey(property("sign.key"))
.signPassphrase(property("sign.passphrase"));
@ -88,12 +88,25 @@ public class DetektOperationBuild extends Project {
new DetektOperationBuild().start(args);
}
@BuildCommand(summary = "Check source code with PMD")
public void pmd() {
@BuildCommand(summary = "Checks source code with PMD")
public void pmd() throws Exception {
new PmdOperation()
.fromProject(this)
.ruleSets("config/pmd.xml")
.execute();
}
@Override
public void test() throws Exception {
var os = System.getProperty("os.name");
if (os != null && os.toLowerCase(Locale.US).contains("linux")) {
new ExecOperation()
.fromProject(this)
.command("scripts/cliargs.sh")
.execute();
}
super.test();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
@ -17,9 +17,14 @@
package rife.bld.extension;
import rife.bld.BaseProject;
import rife.bld.extension.detekt.Report;
import rife.bld.extension.detekt.ReportId;
import rife.bld.operations.AbstractProcessOperation;
import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -43,19 +48,21 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
"kotlin-reflect-",
"kotlin-script-runtime-",
"kotlin-stdlib-",
"kotlin-stdlib-jdk7-",
"kotlin-stdlib-jdk8-",
"kotlinx-coroutines-",
"kotlinx-html-jvm-",
"kotlinx-serialization-",
"poko-annotations-jvm-",
"sarif4k-jvm-",
"snakeyaml-engine-",
"trove4j-");
private static final Logger LOGGER = Logger.getLogger(DetektReport.class.getName());
private final Collection<String> classpath_ = new ArrayList<>();
private final Collection<String> config_ = new ArrayList<>();
private final Collection<String> input_ = new ArrayList<>();
private final Collection<String> plugins_ = new ArrayList<>();
private final Collection<DetektReport> report_ = new ArrayList<>();
private static final Logger LOGGER = Logger.getLogger(DetektOperation.class.getName());
private final Collection<File> classpath_ = new ArrayList<>();
private final Collection<File> config_ = new ArrayList<>();
private final Collection<String> excludes_ = new ArrayList<>();
private final Collection<String> includes_ = new ArrayList<>();
private final Collection<File> input_ = new ArrayList<>();
private final Collection<File> plugins_ = new ArrayList<>();
private final Collection<Report> report_ = new ArrayList<>();
private boolean allRules_;
private boolean autoCorrect_;
private String basePath_;
@ -65,9 +72,7 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
private boolean createBaseline_;
private boolean debug_;
private boolean disableDefaultRuleSets_;
private String excludes_;
private boolean generateConfig_;
private String includes_;
private String jdkHome_;
private String jvmTarget_;
private String languageVersion_;
@ -114,6 +119,39 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
return this;
}
/**
* Specifies a directory as the base path. Currently, it impacts all file
* paths in the formatted reports. File paths in console output and txt
* report are not affected and remain as absolute paths.
*
* @param path the directory path
* @return this operation instance
*/
public DetektOperation basePath(File path) {
return basePath(path.getAbsolutePath());
}
/**
* Retrieves the base path.
*
* @return the directory path
*/
public String basePath() {
return basePath_;
}
/**
* Specifies a directory as the base path. Currently, it impacts all file
* paths in the formatted reports. File paths in console output and txt
* report are not affected and remain as absolute paths.
*
* @param path the directory path
* @return this operation instance
*/
public DetektOperation basePath(Path path) {
return basePath(path.toFile().getAbsolutePath());
}
/**
* If a baseline xml file is passed in, only new code smells not in the
* baseline are printed in the console.
@ -126,6 +164,37 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
return this;
}
/**
* If a baseline xml file is passed in, only new code smells not in the
* baseline are printed in the console.
*
* @param baseline the baseline xml file
* @return this operation instance
*/
public DetektOperation baseline(File baseline) {
return baseline(baseline.getAbsolutePath());
}
/**
* If a baseline xml file is passed in, only new code smells not in the
* baseline are printed in the console.
*
* @param baseline the baseline xml file
* @return this operation instance
*/
public DetektOperation baseline(Path baseline) {
return baseline(baseline.toFile().getAbsolutePath());
}
/**
* Retrieves the baseline xml file.
*
* @return the baseline xml file
*/
public String baseline() {
return baseline_;
}
/**
* Preconfigures detekt with a bunch of rules and some opinionated defaults
* for you. Allows additional provided configurations to override the
@ -140,49 +209,151 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
}
/**
* EXPERIMENTAL: Paths where to find user class files and depending jar files.
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths one or more files
* @return this operation instance
* @see #classPath(Collection)
*/
public DetektOperation classPath(String... paths) {
classpath_.addAll(List.of(paths));
return this;
public DetektOperation classPath(File... paths) {
return classPath(List.of(paths));
}
/**
* EXPERIMENTAL: Paths where to find user class files and depending jar files.
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths the list of files
* @param paths one or more files
* @return this operation instance
* @see #classPathPaths(Collection)
*/
public DetektOperation classPath(Collection<String> paths) {
public DetektOperation classPath(Path... paths) {
return classPathPaths(List.of(paths));
}
/**
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths one or more files
* @return this operation instance
* @see #classPathStrings(Collection)
*/
public DetektOperation classPath(String... paths) {
return classPathStrings(List.of(paths));
}
/**
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths the paths
* @return this operation instance
* @see #classPath(File...)
*/
public DetektOperation classPath(Collection<File> paths) {
classpath_.addAll(paths);
return this;
}
/**
* Path to the config file ({@code path/to/config.yml}).
* Paths where to find user class files and jar dependencies.
*
* @return the paths
*/
public Collection<File> classPath() {
return classpath_;
}
/**
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths the paths
* @return this operation instance
* @see #classPath(Path...)
*/
public DetektOperation classPathPaths(Collection<Path> paths) {
return classPath(paths.stream().map(Path::toFile).toList());
}
/**
* EXPERIMENTAL: Paths where to find user class files and jar dependencies.
* Used for type resolution.
*
* @param paths the paths
* @return this operation instance
* @see #classPath(String...)
*/
public DetektOperation classPathStrings(Collection<String> paths) {
return classPath(paths.stream().map(File::new).toList());
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs one or more config files
* @return this operation instance
* @see #config(Collection)
*/
public DetektOperation config(File... configs) {
return config(List.of(configs));
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs one or more config files
* @return this operation instance
* @see #configPaths(Collection)
*/
public DetektOperation config(Path... configs) {
return configPaths(List.of(configs));
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs one or more config files
* @return this operation instance
* @see #configStrings(Collection)
*/
public DetektOperation config(String... configs) {
config_.addAll(List.of(configs));
return configStrings(List.of(configs));
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs the config files
* @return this operation instance
* @see #config(File...)
*/
public DetektOperation config(Collection<File> configs) {
config_.addAll(configs);
return this;
}
/**
* Path to the config file ({@code path/to/config.yml}).
* Paths to config files.
*
* @param configs the list pf config files
* @return this operation instance
* @return the config files paths.
*/
public DetektOperation config(Collection<String> configs) {
config_.addAll(configs);
return this;
public Collection<File> config() {
return config_;
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs the config files
* @return this operation instance
* @see #config(Path...)
*/
public DetektOperation configPaths(Collection<Path> configs) {
return config(configs.stream().map(Path::toFile).toList());
}
/**
@ -196,6 +367,47 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
return this;
}
/**
* Path to the config resource on detekt's classpath ({@code path/to/config.yml}).
*
* @param resource the config resource path
* @return this operation instance
*/
public DetektOperation configResource(File resource) {
return configResource(resource.getAbsolutePath());
}
/**
* Path to the config resource on detekt's classpath ({@code path/to/config.yml}).
*
* @param resource the config resource path
* @return this operation instance
*/
public DetektOperation configResource(Path resource) {
return configResource(resource.toFile().getAbsolutePath());
}
/**
* Retrieves the path of the config resource.
*
* @return the config resource path
*/
public String configResource() {
return configResource_;
}
/**
* Paths to the config files ({@code path/to/config.yml}).
*
* @param configs the config files
* @return this operation instance
* @see #config(String...)
*/
public DetektOperation configStrings(Collection<String> configs) {
config_.addAll(configs.stream().map(File::new).toList());
return this;
}
/**
* Treats current analysis findings as a smell baseline for future detekt
* runs.
@ -233,158 +445,202 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
/**
* Globbing patterns describing paths to exclude from the analysis.
*
* @param patterns the patterns
* @param patterns one or more pattern
* @return this operation instance
*/
public DetektOperation excludes(String patterns) {
excludes_ = patterns;
public DetektOperation excludes(String... patterns) {
return excludes(List.of(patterns));
}
/**
* Globbing patterns describing paths to exclude from the analysis.
*
* @param patterns a collection of patterns
* @return this operation instance
*/
public DetektOperation excludes(Collection<String> patterns) {
excludes_.addAll(patterns);
return this;
}
/**
* Returns the globbing patterns describing paths to exclude from the analysis.
*
* @return the globbing patterns
*/
public Collection<String> excludes() {
return excludes_;
}
/**
* Performs the operation.
*
* @throws InterruptedException when the operation was interrupted
* @throws IOException when an exception occurred during the execution of the process
* @throws ExitStatusException when the exit status was changed during the operation
*/
@Override
public void execute() throws IOException, InterruptedException, ExitStatusException {
if (project_ == null) {
if (LOGGER.isLoggable(Level.SEVERE) && !silent()) {
LOGGER.severe("A project must be specified.");
}
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
} else {
super.execute();
if (successful_ && LOGGER.isLoggable(Level.INFO) && !silent()) {
if (createBaseline_) {
LOGGER.info("Detekt baseline generated successfully: "
+ "file://" + new File(baseline_).toURI().getPath());
} else {
LOGGER.info("Detekt operation finished successfully.");
}
}
}
}
/**
* Part of the {@link #execute} operation, constructs the command list
* to use for building the process.
*/
@Override
protected List<String> executeConstructProcessCommandList() {
if (project_ == null) {
LOGGER.severe("A project must be specified.");
}
final List<String> args = new ArrayList<>();
args.add(javaTool());
args.add("-cp");
args.add(getDetektJarList(project_.libBldDirectory()));
args.add("io.gitlab.arturbosch.detekt.cli.Main");
if (project_ != null) {
args.add(javaTool());
args.add("-cp");
args.add(getDetektJarList(project_.libBldDirectory()));
args.add("io.gitlab.arturbosch.detekt.cli.Main");
// all-rules
if (allRules_) {
args.add("--all-rules");
}
// all-rules
if (allRules_) {
args.add("--all-rules");
}
// auto-correct
if (autoCorrect_) {
args.add("--auto-correct");
}
// auto-correct
if (autoCorrect_) {
args.add("--auto-correct");
}
// base-path
if (isNotBlank(basePath_)) {
args.add("--base-path");
args.add(basePath_);
}
// base-path
if (isNotBlank(basePath_)) {
args.add("--base-path");
args.add(basePath_);
}
// baseline
if (isNotBlank(baseline_)) {
args.add("--baseline");
args.add(baseline_);
}
// baseline
if (isNotBlank(baseline_)) {
args.add("--baseline");
args.add(baseline_);
}
// build-upon-default-config
if (buildUponDefaultConfig_) {
args.add("--build-upon-default-config");
}
// build-upon-default-config
if (buildUponDefaultConfig_) {
args.add("--build-upon-default-config");
}
// classpath
if (!classpath_.isEmpty()) {
args.add("--classpath");
args.add(String.join(File.pathSeparator, classpath_.stream().filter(this::isNotBlank).toList()));
}
// classpath
if (!classpath_.isEmpty()) {
args.add("--classpath");
args.add(String.join(File.pathSeparator, classpath_.stream().map(File::getAbsolutePath).toList()));
}
// config
if (!config_.isEmpty()) {
args.add("-config");
args.add(String.join(";", config_.stream().filter(this::isNotBlank).toList()));
}
// config
if (!config_.isEmpty()) {
args.add("-config");
args.add(String.join(";", config_.stream().map(File::getAbsolutePath).toList()));
}
// config-resource
if (isNotBlank(configResource_)) {
args.add("--config-resource");
args.add(configResource_);
}
// config-resource
if (isNotBlank(configResource_)) {
args.add("--config-resource");
args.add(configResource_);
}
// create-baseline
if (createBaseline_) {
args.add("--create-baseline");
}
// create-baseline
if (createBaseline_) {
args.add("--create-baseline");
}
// debug
if (debug_) {
args.add("--debug");
}
// debug
if (debug_) {
args.add("--debug");
}
// disable-default-rulesets
if (disableDefaultRuleSets_) {
args.add("--disable-default-rulesets");
}
// disable-default-rulesets
if (disableDefaultRuleSets_) {
args.add("--disable-default-rulesets");
}
// excludes
if (isNotBlank(excludes_)) {
args.add("--excludes");
args.add(excludes_);
}
// excludes
if (!excludes_.isEmpty()) {
args.add("--excludes");
args.add(String.join(",", excludes_));
}
// generate-config
if (generateConfig_) {
args.add("--generate-config");
}
// generate-config
if (generateConfig_) {
args.add("--generate-config");
}
// includes
if (isNotBlank(includes_)) {
args.add("--includes");
args.add(includes_);
}
// includes
if (!includes_.isEmpty()) {
args.add("--includes");
args.add(String.join(",", includes_));
}
// input
if (!input_.isEmpty()) {
args.add("--input");
args.add(String.join(",", input_.stream().filter(this::isNotBlank).toList()));
}
// input
if (!input_.isEmpty()) {
args.add("--input");
args.add(String.join(",", input_.stream().map(File::getAbsolutePath).toList()));
}
// jdk-home
if (isNotBlank(jdkHome_)) {
args.add("--jdk-home");
args.add(jdkHome_);
}
// jdk-home
if (isNotBlank(jdkHome_)) {
args.add("--jdk-home");
args.add(jdkHome_);
}
// jvm-target
if (isNotBlank(jvmTarget_)) {
args.add("--jvm-target");
args.add(jvmTarget_);
}
// jvm-target
if (isNotBlank(jvmTarget_)) {
args.add("--jvm-target");
args.add(jvmTarget_);
}
// language-version
if (isNotBlank(languageVersion_)) {
args.add("--language-version");
args.add(languageVersion_);
}
// language-version
if (isNotBlank(languageVersion_)) {
args.add("--language-version");
args.add(languageVersion_);
}
// max-issues
if (maxIssues_ > 0) {
args.add("--max-issues");
args.add(String.valueOf(maxIssues_));
}
// max-issues
if (maxIssues_ > 0) {
args.add("--max-issues");
args.add(String.valueOf(maxIssues_));
}
// parallel
if (parallel_) {
args.add("--parallel");
}
// parallel
if (parallel_) {
args.add("--parallel");
}
// plugins
if (!plugins_.isEmpty()) {
args.add("--plugins");
args.add(String.join(",", plugins_.stream().filter(this::isNotBlank).toList()));
}
// plugins
if (!plugins_.isEmpty()) {
args.add("--plugins");
args.add(String.join(",", plugins_.stream().map(File::getAbsolutePath).toList()));
}
// report
if (!report_.isEmpty()) {
report_.forEach(it -> {
args.add("-r");
args.add(it.id().name().toLowerCase() + ":" + it.path());
});
}
// report
if (!report_.isEmpty()) {
report_.forEach(it -> {
args.add("--report");
args.add(it.id().name().toLowerCase() + ":" + it.path());
});
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(String.join(" ", args.stream().filter(this::isNotBlank).toList()));
if (LOGGER.isLoggable(Level.FINE) && !silent()) {
LOGGER.fine(String.join(" ", args.stream().filter(this::isNotBlank).toList()));
}
}
return args;
@ -409,7 +665,7 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
if (baseline.exists()) {
baseline_ = baseline.getAbsolutePath();
}
excludes(".*/build/.*,.*/resources/.*");
excludes(".*/build/.*", ".*/resources/.*");
return this;
}
@ -426,9 +682,7 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
return this;
}
/*
* Retrieves the matching JARs files from the given directory.
*/
// Retrieves the matching JARs files from the given directory.
private String getDetektJarList(File directory) {
var jars = new ArrayList<String>();
@ -447,28 +701,49 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
}
}
}
return String.join(":", jars);
return String.join(File.pathSeparator, jars);
}
/**
* Globbing patterns describing paths to include in the analysis. Useful in
* combination with {@link #excludes(String) excludes} patterns.
* combination with {@link #excludes() excludes} patterns.
*
* @param patterns the patterns
* @param patterns one or more patterns
* @return this operation instance
*/
public DetektOperation includes(String patterns) {
includes_ = patterns;
public DetektOperation includes(String... patterns) {
return includes(List.of(patterns));
}
/**
* Globbing patterns describing paths to include in the analysis. Useful in
* combination with {@link #excludes() excludes} patterns.
*
* @param patterns a collection of patterns
* @return this operation instance
*/
public DetektOperation includes(Collection<String> patterns) {
includes_.addAll(patterns);
return this;
}
/**
* Returns the globbing patterns describing paths to include in the analysis.
*
* @return the globbing patterns
*/
public Collection<String> includes() {
return includes_;
}
/**
* Input paths to analyze. If not specified the current working directory is used.
*
* @param paths the list of paths
* @param paths the paths
* @return this operation instance
* @see #input(Collection)
*/
public DetektOperation input(Collection<String> paths) {
public DetektOperation input(Collection<File> paths) {
input_.addAll(paths);
return this;
}
@ -478,10 +753,32 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
*
* @param paths one or more paths
* @return this operation instance
* @see #inputStrings(Collection)
*/
public DetektOperation input(String... paths) {
input_.addAll(List.of(paths));
return this;
return inputStrings(List.of(paths));
}
/**
* Input paths to analyze. If not specified the current working directory is used.
*
* @param paths one or more paths
* @return this operation instance
* @see #input(Collection)
*/
public DetektOperation input(File... paths) {
return input(List.of(paths));
}
/**
* Input paths to analyze. If not specified the current working directory is used.
*
* @param paths one or more paths
* @return this operation instance
* @see #inputPaths(Collection)
*/
public DetektOperation input(Path... paths) {
return inputPaths(List.of(paths));
}
/**
@ -489,10 +786,32 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
*
* @return the input paths
*/
public Collection<String> input() {
public Collection<File> input() {
return input_;
}
/**
* Input paths to analyze. If not specified the current working directory is used.
*
* @param paths the paths
* @return this operation instance
* @see #input(Path...)
*/
public DetektOperation inputPaths(Collection<Path> paths) {
return input(paths.stream().map(Path::toFile).toList());
}
/**
* Input paths to analyze. If not specified the current working directory is used.
*
* @param paths the paths
* @return this operation instance
* @see #input(String...)
*/
public DetektOperation inputStrings(Collection<String> paths) {
return input(paths.stream().map(File::new).toList());
}
/*
* Determines if a string is not blank.
*/
@ -570,30 +889,84 @@ public class DetektOperation extends AbstractProcessOperation<DetektOperation> {
*
* @param jars one or more jars
* @return this operation instance
* @see #pluginsStrings(Collection)
*/
public DetektOperation plugins(String... jars) {
plugins_.addAll(List.of(jars));
return this;
return pluginsStrings(List.of(jars));
}
/**
* Extra paths to plugin jars.
*
* @param jars the list of jars
* @param jars one or more jars
* @return this operation instance
* @see #plugins(Collection)
*/
public DetektOperation plugins(Collection<String> jars) {
public DetektOperation plugins(File... jars) {
return plugins(List.of(jars));
}
/**
* Extra paths to plugin jars.
*
* @param jars one or more jars
* @return this operation instance
* @see #pluginsPaths(Collection)
*/
public DetektOperation plugins(Path... jars) {
return pluginsPaths(List.of(jars));
}
/**
* Extra paths to plugin jars.
*
* @param jars the jars paths
* @return this operation instance
* @see #input(File...)
*/
public DetektOperation plugins(Collection<File> jars) {
plugins_.addAll(jars);
return this;
}
/**
* Generates a report for given {@link DetektReportId report-id} and stores it on given 'path'.
* Extra path to plugins jars.
*
* @return the jars paths
*/
public Collection<File> plugins() {
return plugins_;
}
/**
* Extra paths to plugin jars.
*
* @param jars the jars paths
* @return this operation instance
* @see #plugins(Path...)
*/
public DetektOperation pluginsPaths(Collection<Path> jars) {
return plugins(jars.stream().map(Path::toFile).toList());
}
/**
* Extra paths to plugin jars.
*
* @param jars the jars paths
* @return this operation instance
* @see #plugins(String...)
*/
public DetektOperation pluginsStrings(Collection<String> jars) {
return plugins(jars.stream().map(File::new).toList());
}
/**
* Generates a report for given {@link ReportId report-id} and stores it on given 'path'.
*
* @param reports one or more reports
* @return this operation instance
*/
public DetektOperation report(DetektReport... reports) {
public DetektOperation report(Report... reports) {
report_.addAll(List.of(reports));
return this;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
@ -14,15 +14,15 @@
* limitations under the License.
*/
package rife.bld.extension;
package rife.bld.extension.detekt;
/**
* Defines a report for given report-id to be stores in the given path.
* Defines a report for the given report-id to be stored on the given path.
*
* @param id the report-id
* @param path the given path
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.0
*/
public record DetektReport(DetektReportId id, String path) {
public record Report(ReportId id, String path) {
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package rife.bld.extension;
package rife.bld.extension.detekt;
/**
* The report-id values.
@ -22,6 +22,6 @@ package rife.bld.extension;
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.0
*/
public enum DetektReportId {
public enum ReportId {
TXT, XML, HTML, MD, SARIF
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
@ -16,14 +16,21 @@
package rife.bld.extension;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import rife.bld.BaseProject;
import rife.bld.blueprints.BaseProjectBlueprint;
import rife.bld.extension.detekt.Report;
import rife.bld.extension.detekt.ReportId;
import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.logging.ConsoleHandler;
@ -32,7 +39,6 @@ import java.util.logging.Logger;
import static org.assertj.core.api.Assertions.*;
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
class DetektOperationTest {
@BeforeAll
@ -57,16 +63,193 @@ class DetektOperationTest {
}
}
@Test
void testBasePath() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().basePath(foo);
assertThat(op.basePath()).as("as file").isEqualTo(foo.getAbsolutePath());
op = op.basePath(bar.toPath());
assertThat(op.basePath()).as("as path").isEqualTo(bar.getAbsolutePath());
op = op.basePath("foo");
assertThat(op.basePath()).as("as string").isEqualTo("foo");
}
@Test
void testBaseline() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().baseline(foo);
assertThat(op.baseline()).as("as file").isEqualTo(foo.getAbsolutePath());
op = op.baseline(bar.toPath());
assertThat(op.baseline()).as("as path").isEqualTo(bar.getAbsolutePath());
op = op.baseline("foo");
assertThat(op.baseline()).as("as string").isEqualTo("foo");
}
@Test
@EnabledOnOs(OS.LINUX)
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
void testCheckAllParameters() throws IOException {
var args = Files.readAllLines(Paths.get("src", "test", "resources", "detekt-args.txt"));
assertThat(args).isNotEmpty();
var op = new DetektOperation()
.fromProject(new BaseProject())
.allRules(true)
.autoCorrect(true)
.basePath("basePath")
.basePath(new File("basePath"))
.baseline("baseline")
.buildUponDefaultConfig(true)
.classPath(new File("path1"))
.classPath("path2", "path3")
.classPath(List.of(new File("path4"), new File("path5")))
.config(new File("config1"))
.config("config2", "config3")
.config(List.of(new File("config4"), new File("config5")))
.configResource("configResource")
.configResource(new File("configResource"))
.createBaseline(true)
.debug(true)
.disableDefaultRuleSets(true)
.excludes(List.of("excludes1", "excludes2"))
.excludes("excludes3", "excludes4")
.generateConfig(true)
.includes(List.of("includes1", "includes2"))
.includes("includes3", "includes4", "includes5")
.input(new File("input1"))
.input("input2", "input3")
.input(List.of(new File("input4"), new File("input5")))
.jdkHome("jdkHome")
.jvmTarget("jvmTarget")
.languageVersion("languageVersion")
.maxIssues(10)
.parallel(true)
.plugins(new File("jar1"))
.plugins("jar2", "jar3")
.plugins(List.of(new File("jar4"), new File("jar5")))
.report(new Report(ReportId.HTML, "reports"));
assertThat(op.excludes()).as("excludes[]").containsExactly(".*/build/.*", ".*/resources/.*",
"excludes1", "excludes2", "excludes3", "excludes4");
for (var i = 1; i < 6; i++) {
assertThat(op.classPath()).as("classPath[" + i + ']').hasSize(5).contains(new File("path" + i));
assertThat(op.config()).as("config[" + i + ']').hasSize(5).contains(new File("config" + i));
assertThat(op.includes()).as("includes[" + i + ']').hasSize(5).contains("includes" + i);
assertThat(op.input()).as("input[" + i + ']').hasSize(5).contains(new File("input" + i));
assertThat(op.plugins()).as("plugins[" + i + ']').hasSize(5).contains(new File("jar" + i));
}
var params = op.executeConstructProcessCommandList();
try (var softly = new AutoCloseableSoftAssertions()) {
for (var p : args) {
var found = false;
for (var a : params) {
if (a.startsWith(p)) {
found = true;
break;
}
}
softly.assertThat(found).as(p + " not found.").isTrue();
}
}
}
@Test
void testClassPath() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().classPath("foo", "bar");
assertThat(op.classPath()).as("String...").contains(foo, bar);
op.classPath().clear();
op = op.classPath(foo, bar);
assertThat(op.classPath()).as("File...").contains(foo, bar);
op.classPath().clear();
op = op.classPath(foo.toPath(), bar.toPath());
assertThat(op.classPath()).as("Path...").contains(foo, bar);
op.classPath().clear();
op = op.classPathStrings(List.of("foo", "bar"));
assertThat(op.classPath()).as("List(String...)").contains(foo, bar);
op.classPath().clear();
op = op.classPath(List.of(foo, bar));
assertThat(op.classPath()).as("File...").contains(foo, bar);
op.classPath().clear();
op = op.classPathPaths(List.of(foo.toPath(), bar.toPath()));
assertThat(op.classPath()).as("Path...").contains(foo, bar);
op.classPath().clear();
}
@Test
void testConfig() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().config("foo", "bar");
assertThat(op.config()).as("String...").contains(foo, bar);
op.config().clear();
op = op.config(foo, bar);
assertThat(op.config()).as("File...").contains(foo, bar);
op.config().clear();
op = op.config(foo.toPath(), bar.toPath());
assertThat(op.config()).as("Path...").contains(foo, bar);
op.config().clear();
op = op.configStrings(List.of("foo", "bar"));
assertThat(op.config()).as("List(String...)").contains(foo, bar);
op.config().clear();
op = op.config(List.of(foo, bar));
assertThat(op.config()).as("File...").contains(foo, bar);
op.config().clear();
op = op.configPaths(List.of(foo.toPath(), bar.toPath()));
assertThat(op.config()).as("Path...").contains(foo, bar);
op.config().clear();
}
@Test
void testConfigResource() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().configResource(foo);
assertThat(op.configResource()).as("as file").isEqualTo(foo.getAbsolutePath());
op = op.configResource(bar.toPath());
assertThat(op.configResource()).as("as path").isEqualTo(bar.getAbsolutePath());
op = new DetektOperation().configResource("foo");
assertThat(op.configResource()).as("as string").isEqualTo("foo");
}
@Test
void testExampleBaseline() throws IOException, ExitStatusException, InterruptedException {
var tmpDir = Files.createTempDirectory("bld-detekt-").toFile();
var baseline = new File(tmpDir, "detekt-baseline.xml");
var baseline = new File(tmpDir, "examples/src/test/resources/detekt-baseline.xml");
var op = new DetektOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example",
"Example"))
.baseline(baseline.getAbsolutePath())
"example", "Example"))
.baseline(baseline)
.createBaseline(true);
op.execute();
@ -80,7 +263,7 @@ class DetektOperationTest {
void testExampleMaxIssues() {
var op = new DetektOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example",
"Example"))
"example", "Example"))
.maxIssues(8);
assertThatNoException().isThrownBy(op::execute);
}
@ -97,12 +280,12 @@ class DetektOperationTest {
var op = new DetektOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example",
"Example"))
.report(new DetektReport(DetektReportId.HTML, html.getAbsolutePath()))
.report(new DetektReport(DetektReportId.XML, xml.getAbsolutePath()))
.report(new DetektReport(DetektReportId.TXT, txt.getAbsolutePath()))
.report(new DetektReport(DetektReportId.MD, md.getAbsolutePath()))
.report(new DetektReport(DetektReportId.SARIF, sarif.getAbsolutePath()));
"example", "Example"))
.report(new Report(ReportId.HTML, html.getAbsolutePath()))
.report(new Report(ReportId.XML, xml.getAbsolutePath()))
.report(new Report(ReportId.TXT, txt.getAbsolutePath()))
.report(new Report(ReportId.MD, md.getAbsolutePath()))
.report(new Report(ReportId.SARIF, sarif.getAbsolutePath()));
assertThatThrownBy(op::execute).isInstanceOf(ExitStatusException.class);
@ -115,8 +298,74 @@ class DetektOperationTest {
void testExamplesExecute() {
var op = new DetektOperation()
.fromProject(new BaseProjectBlueprint(new File("examples"), "com.example",
"Example"))
"example", "Example"))
.debug(true);
assertThatThrownBy(op::execute).isInstanceOf(ExitStatusException.class);
}
@Test
void testExecuteNoProject() {
var op = new DetektOperation();
assertThatCode(op::execute).isInstanceOf(ExitStatusException.class);
}
@Test
void testInput() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().input("foo", "bar");
assertThat(op.input()).as("String...").contains(foo, bar);
op.input().clear();
op = op.input(foo, bar);
assertThat(op.input()).as("File...").contains(foo, bar);
op.input().clear();
op = op.input(foo.toPath(), bar.toPath());
assertThat(op.input()).as("Path...").contains(foo, bar);
op.input().clear();
op = op.inputStrings(List.of("foo", "bar"));
assertThat(op.input()).as("List(String...)").contains(foo, bar);
op.input().clear();
op = op.input(List.of(foo, bar));
assertThat(op.input()).as("File...").contains(foo, bar);
op.input().clear();
op = op.inputPaths(List.of(foo.toPath(), bar.toPath()));
assertThat(op.input()).as("Path...").contains(foo, bar);
op.input().clear();
}
@Test
void testPlugins() {
var foo = new File("foo");
var bar = new File("bar");
var op = new DetektOperation().plugins("foo", "bar");
assertThat(op.plugins()).as("String...").contains(foo, bar);
op.plugins().clear();
op = op.plugins(foo, bar);
assertThat(op.plugins()).as("File...").contains(foo, bar);
op.plugins().clear();
op = op.plugins(foo.toPath(), bar.toPath());
assertThat(op.plugins()).as("Path...").contains(foo, bar);
op.plugins().clear();
op = op.pluginsStrings(List.of("foo", "bar"));
assertThat(op.plugins()).as("List(String...)").contains(foo, bar);
op.plugins().clear();
op = op.plugins(List.of(foo, bar));
assertThat(op.plugins()).as("File...").contains(foo, bar);
op.plugins().clear();
op = op.pluginsPaths(List.of(foo.toPath(), bar.toPath()));
assertThat(op.plugins()).as("Path...").contains(foo, bar);
op.plugins().clear();
}
}

View file

@ -0,0 +1,21 @@
--all-rules
--auto-correct
--baseline
--base-path
--build-upon-default-config
--classpath
--config
--config-resource
--create-baseline
--debug
--disable-default-rulesets
--excludes
--generate-config
--includes
--input
--jdk-home
--jvm-target
--max-issues
--parallel
--plugins
--report