Skip to content

Commit e2211ce

Browse files
authored
Snippet scan summary (#1613)
1 parent 29614a0 commit e2211ce

File tree

4 files changed

+80
-16
lines changed

4 files changed

+80
-16
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# FOSSA CLI Changelog
22

3+
## 3.13.1
4+
- Add a summary of the snippet scan when the `--x-snippet-scan` flag is used ([#1613](https://github.com/fossas/fossa-cli/pull/1613))
5+
36
## 3.13.0
47
- Change how debug logs are generated. They are now generated in a file called fossa.debug.zip, which can contain multiple files. For the common case of `fossa analyze --debug`, it will now contain the debug bundle (fossa.debug.json) and the telemetry json (fossa.telemetry.json). It will also contain Ficus logs if Ficus is run via --x-snippet-scan ([#1610](https://github.com/fossas/fossa-cli/pull/1610))
58

integration-test/Analysis/FicusSpec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ spec = do
5656
case result of
5757
Success _warnings analysisResult -> do
5858
case analysisResult of
59-
Just (FicusSnippetScanResults analysisId) -> do
60-
analysisId `shouldSatisfy` (> 0)
59+
Just results -> do
60+
ficusSnippetScanResultsAnalysisId results `shouldSatisfy` (> 0)
6161
Nothing -> do
6262
-- No snippet scan results returned - this is acceptable for integration testing
6363
True `shouldBe` True

src/App/Fossa/Ficus/Analyze.hs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import App.Fossa.Ficus.Types (
2121
FicusMessageData (..),
2222
FicusMessages (..),
2323
FicusPerStrategyFlag (..),
24+
FicusScanStats (..),
2425
FicusSnippetScanResults (..),
2526
)
2627
import App.Types (ProjectRevision (..))
@@ -29,8 +30,7 @@ import Control.Carrier.Diagnostics (Diagnostics)
2930
import Control.Concurrent.Async (async, wait)
3031
import Control.Effect.Lift (Has, Lift, sendIO)
3132
import Control.Monad (when)
32-
import Data.Aeson (Object, decode, decodeStrictText, (.:))
33-
import Data.Aeson.Types (parseMaybe)
33+
import Data.Aeson (decode, decodeStrictText)
3434
import Data.ByteString.Lazy qualified as BL
3535
import Data.Conduit ((.|))
3636
import Data.Conduit qualified as Conduit
@@ -64,6 +64,7 @@ import System.Process.Typed (
6464
waitExitCode,
6565
withProcessWait,
6666
)
67+
import Text.Printf (printf)
6768
import Text.URI (render)
6869
import Text.URI.Builder (PathComponent (PathComponent), TrailingSlash (TrailingSlash), setPath)
6970
import Types (GlobFilter (..), LicenseScanPathFilters (..))
@@ -116,7 +117,7 @@ analyzeWithFicusMain rootDir apiOpts revision filters snippetScanRetentionDays m
116117
logDebugWithTime "runFicus completed, processing results..."
117118
case ficusResults of
118119
Just results ->
119-
logInfo $ "Ficus analysis completed successfully with analysis ID: " <> pretty (ficusSnippetScanResultsAnalysisId results)
120+
logInfo $ pretty (formatFicusScanSummary results)
120121
Nothing -> logInfo "Ficus analysis completed but no fingerprint findings were found"
121122
pure ficusResults
122123
where
@@ -131,13 +132,37 @@ analyzeWithFicusMain rootDir apiOpts revision filters snippetScanRetentionDays m
131132
, ficusConfigSnippetScanRetentionDays = snippetScanRetentionDays
132133
}
133134

134-
findingToAnalysisId :: FicusFinding -> Maybe Int
135-
findingToAnalysisId (FicusFinding (FicusMessageData strategy payload))
135+
findingToSnippetScanResult :: FicusFinding -> Maybe FicusSnippetScanResults
136+
findingToSnippetScanResult (FicusFinding (FicusMessageData strategy payload))
136137
| Text.toLower strategy == "fingerprint" =
137-
case decode (BL.fromStrict $ Text.Encoding.encodeUtf8 payload) :: Maybe Object of
138-
Just obj -> parseMaybe (.: "analysis_id") obj
139-
Nothing -> Nothing
140-
findingToAnalysisId _ = Nothing
138+
decode (BL.fromStrict $ Text.Encoding.encodeUtf8 payload)
139+
findingToSnippetScanResult _ = Nothing
140+
141+
formatFicusScanSummary :: FicusSnippetScanResults -> Text
142+
formatFicusScanSummary results =
143+
let stats = ficusSnippetScanResultsStats results
144+
aid = ficusSnippetScanResultsAnalysisId results
145+
in Text.unlines
146+
[ "Ficus snippet scan completed successfully!"
147+
, ""
148+
, "============================================================"
149+
, "Snippet scan summary:"
150+
, " Analysis ID: " <> toText (show aid)
151+
, " Bucket ID: " <> toText (show $ ficusSnippetScanResultsBucketId results)
152+
, " Files skipped: " <> toText (show $ ficusStatsSkippedFiles stats)
153+
, " Total Files processed: " <> toText (show $ ficusStatsProcessedFiles stats)
154+
, " Unique Files processed: " <> toText (show $ ficusStatsUniqueProcessedFiles stats)
155+
, " Unique Files with matches found: " <> toText (show $ ficusStatsUniqueMatchedFiles stats)
156+
, " Unique Files with no matches found: " <> toText (show $ ficusStatsUniqueUnmatchedFiles stats)
157+
, " Unique Files already in our knowledge base: " <> toText (show $ ficusStatsUniqueExistingFiles stats)
158+
, " Unique Files new to our knowledge base: " <> toText (show $ ficusStatsUniqueNewFiles stats)
159+
, " Processing time: " <> formatProcessingTime (ficusStatsProcessingTimeSeconds stats) <> "s"
160+
, "============================================================"
161+
]
162+
where
163+
-- Format the processing time as a string with 3 decimal places
164+
formatProcessingTime :: Double -> Text
165+
formatProcessingTime seconds = toText (printf "%.3f" seconds :: String)
141166

142167
runFicus ::
143168
( Has Diagnostics sig m
@@ -236,10 +261,10 @@ runFicus maybeDebugDir ficusConfig = do
236261
pure acc
237262
FicusMessageFinding finding -> do
238263
hPutStrLn stderr $ "[" ++ timestamp ++ "] FINDING " <> toString (displayFicusFinding finding)
239-
let analysisFinding = FicusSnippetScanResults <$> findingToAnalysisId finding
264+
let analysisFinding = findingToSnippetScanResult finding
240265
when (isJust acc && isJust analysisFinding) $
241266
hPutStrLn stderr $
242-
"[" ++ timestamp ++ "] ERROR " <> "Found multiple analysis ids."
267+
"[" ++ timestamp ++ "] ERROR " <> "Found multiple ficus analysis responses."
243268
pure $ acc <|> analysisFinding
244269
)
245270
Nothing

src/App/Fossa/Ficus/Types.hs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ module App.Fossa.Ficus.Types (
1313
FicusHashFlag (..),
1414
FicusSnippetScanFlag,
1515
FicusSnippetScanResults (..),
16+
FicusScanStats (..),
1617
FicusPerStrategyFlag (..),
1718
) where
1819

1920
import App.Types (ProjectRevision)
20-
import Data.Aeson (FromJSON, Value (Object), withText)
21-
import Data.Aeson qualified as A
21+
import Data.Aeson (FromJSON (parseJSON), Value (Object), withObject, withText)
2222
import Data.Aeson.Types (Parser, (.:))
2323
import Data.Text (Text)
2424
import Fossa.API.Types
@@ -27,7 +27,43 @@ import Path (Abs, Dir, Path)
2727
import Text.URI
2828
import Types (GlobFilter)
2929

30-
newtype FicusSnippetScanResults = FicusSnippetScanResults {ficusSnippetScanResultsAnalysisId :: Int} deriving (Eq, Ord, Show, Generic)
30+
data FicusSnippetScanResults = FicusSnippetScanResults
31+
{ ficusSnippetScanResultsAnalysisId :: Int
32+
, ficusSnippetScanResultsBucketId :: Int
33+
, ficusSnippetScanResultsStats :: FicusScanStats
34+
}
35+
deriving (Eq, Ord, Show, Generic)
36+
37+
instance FromJSON FicusSnippetScanResults where
38+
parseJSON = withObject "FicusSnippetScanResults" $ \obj ->
39+
FicusSnippetScanResults
40+
<$> obj .: "analysis_id"
41+
<*> obj .: "bucket_id"
42+
<*> obj .: "stats"
43+
44+
data FicusScanStats = FicusScanStats
45+
{ ficusStatsSkippedFiles :: Int
46+
, ficusStatsProcessedFiles :: Int
47+
, ficusStatsUniqueProcessedFiles :: Int
48+
, ficusStatsUniqueNewFiles :: Int
49+
, ficusStatsUniqueExistingFiles :: Int
50+
, ficusStatsUniqueMatchedFiles :: Int
51+
, ficusStatsUniqueUnmatchedFiles :: Int
52+
, ficusStatsProcessingTimeSeconds :: Double
53+
}
54+
deriving (Eq, Ord, Show, Generic)
55+
56+
instance FromJSON FicusScanStats where
57+
parseJSON = withObject "FicusScanStats" $ \obj ->
58+
FicusScanStats
59+
<$> obj .: "skipped_files"
60+
<*> obj .: "processed_files"
61+
<*> obj .: "unique_processed_files"
62+
<*> obj .: "unique_new_files"
63+
<*> obj .: "unique_existing_files"
64+
<*> obj .: "unique_matched_files"
65+
<*> obj .: "unique_unmatched_files"
66+
<*> obj .: "processing_time_seconds"
3167

3268
data FicusMessages = FicusMessages
3369
{ ficusMessageDebugs :: [FicusDebug]

0 commit comments

Comments
 (0)