Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update README and move sarif utils into common module #477

Merged
merged 6 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,19 @@ fun Path.parentsWithSelf() = listOf(this) + this.parents().toList()
*/
expect fun FileSystem.myDeleteRecursively(path: Path)

/**
* Find a file in any of parent directories and return this directory
*
* @param path path for which ancestors should be checked
* @param fileName a name of the file that will be searched for
* @return a path to one of parent directories or null if no directory contains [fileName]
*/
fun FileSystem.findAncestorDirContainingFile(path: Path, fileName: String): Path? = path.parents().firstOrNull { parent ->
metadata(parent).isDirectory && list(parent).any {
it.name == fileName
}
}

/**
* @return current working directory
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Utility methods to work with SARIF files.
*/

package com.saveourtool.save.core.utils

import com.saveourtool.save.core.files.findAncestorDirContainingFile
import com.saveourtool.save.core.files.fs
import com.saveourtool.save.core.files.parents
import com.saveourtool.save.core.plugin.PluginException

import okio.FileSystem
import okio.Path

/**
* @return string with trimmed `file://` or `file:///`
*/
fun String.dropFileProtocol() = substringAfter("file://")
.let {
// It is a valid format for Windows paths to look like `file:///C:/stuff`
if (it[0] == '/' && it[2] == ':') it.drop(1) else it
}

/**
* Make all paths in [this] collection relative to [root]
*
* @param root a common root for files in [this]
* @return a list of relative paths
*/
fun List<Path>.adjustToCommonRoot(root: Path) = map {
it.relativeTo(root).normalized()
}

/**
* Find the last parent directory containing save.toml.
*
* @param path a path to start the search
* @return one of parent directories
*/
fun FileSystem.topmostTestDirectory(path: Path): Path = path.parents().last { parent ->
list(parent).any { it.name == "save.toml" }
}

/**
* Calculate the path to sarif file; we expect, that it single for the all tests and located in one of parent directories
* for evaluated test files
*
* @param sarifFileName sarif file name
* @param anchorTestFilePath anchor file for calculating corresponding sarif file;
* since .sarif file expected to be the one for all test files, it could be any of test file
* @return path to sarif
* @throws PluginException in case of absence of sarif file
*/
fun calculatePathToSarifFile(sarifFileName: String, anchorTestFilePath: Path): Path = fs.findAncestorDirContainingFile(
anchorTestFilePath, sarifFileName
)?.let {
it / sarifFileName
} ?: throw PluginException(
"Could not find SARIF file with expected warnings/fixes for file $anchorTestFilePath. " +
"Please check if correct `FarningsFormat`/`FixFormat` is set (should be SARIF) and if the file is present and called `$sarifFileName`."
)
6 changes: 6 additions & 0 deletions save-plugins/fix-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Save fix plugin
Plugin that runs provided executable on the initial file with a test source code and compares its output with an expected result.

Fix plugin supports two types of execution: `IN_PLACE` and `SARIF`, which could be specified by `actualFixFormat` flag.
In case of `IN_PLACE` mode, `save` will apply fixes, obtained by static analysis tool by executing it with provided configuration,
while in `SARIF` mode, it will expect the `.sarif` file, with the list of fixes, which could be provided by `actualFixSarifFileName` flag.
Plugin will extract all fixes from sarif and apply them to the test files. More information about sarif fix sections could be found [here](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317881).

Please note, that it is important for test resources to have specific postfixes. By the default test file it should be `Test`
, for the file with expected result - it should be `Expected`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.saveourtool.save.core.utils.ExecutionResult
import com.saveourtool.save.core.utils.PathSerializer
import com.saveourtool.save.core.utils.ProcessExecutionException
import com.saveourtool.save.core.utils.ProcessTimeoutException
import com.saveourtool.save.core.utils.calculatePathToSarifFile
import com.saveourtool.save.core.utils.singleIsInstance

import com.saveourtool.sarifutils.cli.adapter.SarifFixAdapter
Expand Down Expand Up @@ -186,10 +187,15 @@ class FixPlugin(
testsPaths: List<Path>,
testCopyToExpectedFilesMap: List<PathPair>,
): List<PathPair> {
val sarif = calculatePathToSarifFile(
sarifFileName = fixPluginConfig.actualFixSarifFileName!!,
// Since we have one .sarif file for all tests, just take the first of them as anchor for calculation of paths
anchorTestFilePath = testsPaths.first()
)
// In this case fixes weren't performed by tool into the test files directly,
// instead, there was created sarif file with list of fixes, which we will apply ourselves
val fixedFiles = SarifFixAdapter(
sarifFile = fixPluginConfig.actualFixSarifFileName!!.toPath(),
sarifFile = sarif,
targetFiles = testsPaths
).process()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,8 @@ data class FixPluginConfig(
resourceNameExpectedSuffix = resourceNameExpected,
ignoreLines = ignoreLines,
actualFixFormat = actualFixFormat ?: ActualFixFormat.IN_PLACE,
actualFixSarifFileName = calculateActualFixSarifFilePath(),
actualFixSarifFileName = (actualFixSarifFileName ?: "save-fixes.sarif"),
).also {
it.configLocation = this.configLocation
}

// we require from sarif file to be located at the same level as corresponding save.toml
private fun calculateActualFixSarifFilePath(): String? = if (actualFixFormat == ActualFixFormat.SARIF) {
(
configLocation.parent!! /
(actualFixSarifFileName ?: "save-fixes.sarif").toPath()
).toString()
} else {
null
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package com.saveourtool.save.plugin.warn.sarif

import com.saveourtool.save.core.utils.dropFileProtocol
import com.saveourtool.save.core.utils.isCurrentOsWindows
import com.saveourtool.save.plugin.warn.utils.Warning

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ package com.saveourtool.save.plugin.warn.utils
import com.saveourtool.save.core.files.readFile
import com.saveourtool.save.core.plugin.GeneralConfig
import com.saveourtool.save.core.plugin.PluginException
import com.saveourtool.save.core.utils.adjustToCommonRoot
import com.saveourtool.save.core.utils.calculatePathToSarifFile
import com.saveourtool.save.core.utils.topmostTestDirectory
import com.saveourtool.save.plugin.warn.WarnPluginConfig
import com.saveourtool.save.plugin.warn.sarif.adjustToCommonRoot
import com.saveourtool.save.plugin.warn.sarif.findAncestorDirContainingFile
import com.saveourtool.save.plugin.warn.sarif.toWarnings
import com.saveourtool.save.plugin.warn.sarif.topmostTestDirectory

import io.github.detekt.sarif4k.SarifSchema210
import okio.FileSystem
Expand Down Expand Up @@ -114,11 +114,10 @@ internal fun collectWarningsFromSarif(

// Since we have one .sarif file for all tests, just take the first of them as anchor for calculation of paths
val anchorTestFilePath = originalPaths.first()
val sarif = fs.findAncestorDirContainingFile(anchorTestFilePath, sarifFileName)?.let { it / sarifFileName }
?: throw PluginException(
"Could not find SARIF file with expected warnings for file $anchorTestFilePath. " +
"Please check if correct `expectedWarningsFormat` is set and if the file is present and called `$sarifFileName`."
)
val sarif = calculatePathToSarifFile(
sarifFileName = sarifFileName,
anchorTestFilePath = anchorTestFilePath
)
val topmostTestDirectory = fs.topmostTestDirectory(anchorTestFilePath)
return Json.decodeFromString<SarifSchema210>(
fs.readFile(sarif)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.saveourtool.save.plugin.warn.sarif

import com.saveourtool.save.core.files.getWorkingDirectory
import com.saveourtool.save.core.logging.logInfo
import com.saveourtool.save.core.utils.adjustToCommonRoot
import com.saveourtool.save.plugin.warn.utils.Warning

import io.github.detekt.sarif4k.ArtifactLocation
Expand Down