Skip to content

Commit

Permalink
Merge branch 'master' into bugfix/kdoc-throws
Browse files Browse the repository at this point in the history
  • Loading branch information
diphtongue authored Dec 15, 2023
2 parents ef55ae7 + 02c1a7c commit 5b479d8
Show file tree
Hide file tree
Showing 29 changed files with 678 additions and 167 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
# required for correct codecov upload
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin
Expand Down Expand Up @@ -95,7 +95,7 @@ jobs:
# required for correct codecov upload
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
fetch-depth: 0

- name: 'Set up Java 11'
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 11
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/diktat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/diktat_snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
fetch-depth: 0

- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin
Expand Down
60 changes: 45 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,14 @@ jobs:
fetch-depth: 0

- name: 'Set up Java'
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin

- name: 'Publish a release to GitHub'
id: publish-github
uses: gradle/gradle-build-action@v2
with:
gradle-version: wrapper
arguments: |
publishAllPublicationsToGitHubRepository
- name: 'Calculate the release version'
run: |
echo "RELEASE_VERSION=${GITHUB_REF#'refs/tags/v'}" >> $GITHUB_ENV
- name: 'Publish a release to Maven Central'
id: publish-sonatype
Expand All @@ -60,15 +56,49 @@ jobs:
-Pgradle.publish.key=${{ secrets.GRADLE_KEY }}
-Pgradle.publish.secret=${{ secrets.GRADLE_SECRET }}
github_release:
needs: release
name: 'Github Release'
runs-on: ubuntu-latest
steps:
- name: 'Github Release'
- name: 'Publish a release to GitHub'
id: publish-github
uses: gradle/gradle-build-action@v2
with:
gradle-version: wrapper
arguments: |
shadowExecutableJar
publishAllPublicationsToGitHubRepository
- name: 'GitHub Release'
id: create_release
uses: actions/create-release@v1
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
release_name: Release ${{ env.RELEASE_VERSION }}
draft: false
prerelease: false
- name: Upload Diktat CLI to GitHub release
id: upload-release-asset-cli
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./diktat-cli/build/diktat-cli-${{ env.RELEASE_VERSION }}
asset_name: diktat
asset_content_type: application/zip
- name: Upload Diktat CLI for Windows to GitHub release
id: upload-release-asset-cli-win
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./diktat-cli/src/main/script/diktat.cmd
asset_name: diktat.cmd
asset_content_type: application/octet-stream
- name: Upload Diktat ruleset for KtLint to GitHub release
id: upload-release-asset-ruleset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./diktat-ruleset/build/libs/diktat-${{ env.RELEASE_VERSION }}.jar
asset_name: diktat-${{ env.RELEASE_VERSION }}.jar
asset_content_type: application/zip
2 changes: 2 additions & 0 deletions diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE
- name: CONSTANT_UPPERCASE
enabled: true
configuration:
exceptionConstNames: "serialVersionUID"
# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config
- name: ENUM_VALUE
enabled: true
Expand Down
31 changes: 29 additions & 2 deletions diktat-cli/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import com.saveourtool.diktat.buildutils.configurePublications
import com.github.jengelman.gradle.plugins.shadow.ShadowExtension
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.incremental.createDirectory

@Suppress("DSL_SCOPE_VIOLATION", "RUN_IN_SCRIPT") // https://github.com/gradle/gradle/issues/22797
Expand Down Expand Up @@ -60,7 +59,7 @@ sourceSets.getByName("main") {
)
}

tasks.named<ShadowJar>("shadowJar") {
tasks.shadowJar {
archiveClassifier.set("")
manifest {
attributes["Main-Class"] = "com.saveourtool.diktat.DiktatMainKt"
Expand All @@ -69,6 +68,34 @@ tasks.named<ShadowJar>("shadowJar") {
duplicatesStrategy = DuplicatesStrategy.FAIL
}

tasks.register<DefaultTask>("shadowExecutableJar") {
group = "Distribution"
dependsOn(tasks.shadowJar)

val scriptFile = project.file("src/main/script/header-diktat.sh")
val shadowJarFile = tasks.shadowJar
.get()
.outputs
.files
.singleFile
val outputFile = project.layout
.buildDirectory
.file(shadowJarFile.name.removeSuffix(".jar"))

inputs.files(scriptFile, shadowJarFile)
outputs.file(outputFile)

doLast {
outputFile.get()
.asFile
.apply {
writeBytes(scriptFile.readBytes())
appendBytes(shadowJarFile.readBytes())
setExecutable(true, false)
}
}
}

// disable default jar
tasks.named("jar") {
enabled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import com.saveourtool.diktat.api.DiktatReporterCreationArguments
import com.saveourtool.diktat.api.DiktatReporterFactory
import com.saveourtool.diktat.api.DiktatReporterType
import com.saveourtool.diktat.util.isKotlinCodeOrScript
import com.saveourtool.diktat.util.tryToPathIfExists
import com.saveourtool.diktat.util.walkByGlob
import com.saveourtool.diktat.util.listFiles

import generated.DIKTAT_VERSION
import org.apache.logging.log4j.LogManager
Expand Down Expand Up @@ -96,16 +95,8 @@ data class DiktatProperties(
)
}

private fun getFiles(sourceRootDir: Path): Collection<Path> = patterns
.asSequence()
.flatMap { pattern ->
pattern.tryToPathIfExists()?.let { sequenceOf(it) }
?: sourceRootDir.walkByGlob(pattern)
}
private fun getFiles(sourceRootDir: Path): Collection<Path> = sourceRootDir.listFiles(patterns = patterns.toTypedArray())
.filter { file -> file.isKotlinCodeOrScript() }
.map { it.normalize() }
.map { it.toAbsolutePath() }
.distinct()
.toList()

private fun getReporterOutput(): OutputStream? = output
Expand Down
77 changes: 60 additions & 17 deletions diktat-cli/src/main/kotlin/com/saveourtool/diktat/util/CliUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,96 @@
package com.saveourtool.diktat.util

import java.io.File
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.InvalidPathException
import java.nio.file.Path
import java.nio.file.PathMatcher
import java.nio.file.Paths
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.PathWalkOption
import kotlin.io.path.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.exists
import kotlin.io.path.walk

private const val NEGATIVE_PREFIX_PATTERN = "!"
private const val PARENT_DIRECTORY_PREFIX = 3
private const val PARENT_DIRECTORY_UNIX = "../"
private const val PARENT_DIRECTORY_WINDOWS = "..\\"

// all roots
private val roots: Set<String> = FileSystems.getDefault()
.rootDirectories
.asSequence()
.map { it.absolutePathString() }
.toSet()

/**
* Lists all files in [this] directory based on [patterns]
*
* @param patterns a path to a file or a directory (all files from this directory will be returned) or an [Ant-style path pattern](https://ant.apache.org/manual/dirtasks.html#patterns)
* @return [Sequence] of files as [Path] matched to provided [patterns]
*/
fun Path.listFiles(
vararg patterns: String,
): Sequence<Path> {
val (includePatterns, excludePatterns) = patterns.partition { !it.startsWith(NEGATIVE_PREFIX_PATTERN) }
val exclude by lazy {
doListFiles(excludePatterns.map { it.removePrefix(NEGATIVE_PREFIX_PATTERN) })
.toSet()
}
return doListFiles(includePatterns).filterNot { exclude.contains(it) }
}

@OptIn(ExperimentalPathApi::class)
private fun Path.doListFiles(patterns: List<String>): Sequence<Path> = patterns
.asSequence()
.flatMap { pattern ->
tryToResolveIfExists(pattern, this)?.walk() ?: walkByGlob(pattern)
}
.map { it.normalize() }
.map { it.toAbsolutePath() }
.distinct()

/**
* Create a matcher and return a filter that uses it.
*
* @param glob glob pattern to filter files
* @return a sequence of files which matches to [glob]
*/
@OptIn(ExperimentalPathApi::class)
fun Path.walkByGlob(glob: String): Sequence<Path> = fileSystem.globMatcher(glob)
.let { matcher ->
this.walk(PathWalkOption.INCLUDE_DIRECTORIES)
.filter { matcher.matches(it) }
private fun Path.walkByGlob(glob: String): Sequence<Path> = if (glob.startsWith(PARENT_DIRECTORY_UNIX) || glob.startsWith(PARENT_DIRECTORY_WINDOWS)) {
parent?.walkByGlob(glob.substring(PARENT_DIRECTORY_PREFIX)) ?: emptySequence()
} else {
getAbsoluteGlobAndRoot(glob, this)
.let { (absoluteGlob, root) ->
absoluteGlob
.replace("([^\\\\])\\\\([^\\\\])".toRegex(), "$1\\\\\\\\$2") // encode Windows separators
.let { root.fileSystem.getPathMatcher("glob:$it") }
.let { matcher ->
root.walk().filter { matcher.matches(it) }
}
}
}

private fun String.findRoot(): Path = substring(0, indexOf('*'))
.let { withoutAsterisks ->
withoutAsterisks.substring(0, withoutAsterisks.lastIndexOfAny(charArrayOf('\\', '/')))
}
.let { Path(it) }

/**
* @param candidate
* @param currentDirectory
* @return path or null if path is invalid or doesn't exist
*/
fun String.tryToPathIfExists(): Path? = try {
Paths.get(this).takeIf { it.exists() }
private fun tryToResolveIfExists(candidate: String, currentDirectory: Path): Path? = try {
Paths.get(candidate).takeIf { it.exists() }
?: currentDirectory.resolve(candidate).takeIf { it.exists() }
} catch (e: InvalidPathException) {
null
}

private fun FileSystem.globMatcher(glob: String): PathMatcher = if (isAbsoluteGlob(glob)) {
getPathMatcher("glob:${glob.toUnixSeparator()}")
} else {
getPathMatcher("glob:**/${glob.toUnixSeparator()}")
private fun getAbsoluteGlobAndRoot(glob: String, currentFolder: Path): Pair<String, Path> = when {
glob.startsWith("**") -> glob to currentFolder
roots.any { glob.startsWith(it, true) } -> glob to glob.findRoot()
else -> "${currentFolder.absolutePathString()}${File.separatorChar}$glob" to currentFolder
}

private fun String.toUnixSeparator(): String = replace(File.separatorChar, '/')

private fun isAbsoluteGlob(glob: String): Boolean = glob.startsWith("**") || roots.any { glob.startsWith(it, true) }
19 changes: 19 additions & 0 deletions diktat-cli/src/main/script/diktat.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@echo off

rem
rem diKTat command-line client for Windows
rem
rem Uses Git Bash, so requires Git to be installed.
rem

set "git_install_location=%ProgramFiles%\Git"
set "git_url=https://github.com/git-for-windows/git/releases/latest"

if exist "%git_install_location%" (
setlocal
set "PATH=%git_install_location%\usr\bin;%PATH%"
for /f "usebackq tokens=*" %%p in (`cygpath "%~dpn0"`) do bash --noprofile --norc %%p %*
) else (
echo Expecting Git for Windows at %git_install_location%; please install it from %git_url%
start %git_url%
)
Loading

0 comments on commit 5b479d8

Please sign in to comment.