From 968ed2da749681040e2c6bc9b566b27601645b61 Mon Sep 17 00:00:00 2001 From: Jessica Black Date: Wed, 11 Sep 2024 17:46:24 -0700 Subject: [PATCH] Convert MSB errors to warnings (#1469) --- Changelog.md | 5 ++++ src/App/Fossa/VSI/IAT/Resolve.hs | 34 +++++++++++++-------------- test/App/Fossa/VSI/IAT/ResolveSpec.hs | 11 ++++++--- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Changelog.md b/Changelog.md index 8a116e2681..5426324eab 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,10 @@ # FOSSA CLI Changelog + +## 3.9.33 + +- MSB: Failure to resolve a linked project no longer causes the scan to fail ([[#1469](https://github.com/fossas/fossa-cli/pull/1469)]). + ## 3.9.32 - Platform Support: Add a binary for ARM64 Linux environments. ([#1465](https://github.com/fossas/fossa-cli/pull/1465)) diff --git a/src/App/Fossa/VSI/IAT/Resolve.hs b/src/App/Fossa/VSI/IAT/Resolve.hs index b42db49258..d4ca289454 100644 --- a/src/App/Fossa/VSI/IAT/Resolve.hs +++ b/src/App/Fossa/VSI/IAT/Resolve.hs @@ -13,12 +13,13 @@ import App.Fossa.VSI.IAT.Types ( import App.Fossa.VSI.IAT.Types qualified as IAT import App.Fossa.VSI.Types qualified as VSI import Control.Algebra (Has) -import Control.Effect.Diagnostics (Diagnostics, context, fatalText, recover) +import Control.Effect.Diagnostics (Diagnostics, context, recover, warn) import Control.Effect.FossaApiClient (FossaApiClient, resolveProjectDependencies, resolveUserDefinedBinary) -import Data.Maybe (fromMaybe, isNothing) +import Control.Monad (unless) +import Data.Either (partitionEithers) import Data.String.Conversion (toText) import Data.Text (Text, intercalate) -import Graphing (Graphing, direct, edges, empty) +import Graphing (Graphing, direct, edges) import Srclib.Types ( SourceUserDefDep (..), ) @@ -48,30 +49,29 @@ resolveGraph locators skipResolving = context ("Resolving graph for " <> toText -- This typically means that the user doesn't have access to the project, or the project doesn't exist. -- Collect failed locators and report them to the user, along with mitigation suggestions. subgraphs <- traverseZipM (resolveSubgraph skipResolving) locators - if any resolutionFailed subgraphs - then fatalText $ resolveGraphFailureBundle subgraphs - else pure . mconcat $ fmap unwrap subgraphs + let (warned, success) = partitionMap partitionSubgraph subgraphs + renderWarnings warned + pure $ mconcat success where - resolutionFailed (_, b) = isNothing b - unwrap (_, b) = fromMaybe empty b + renderWarnings subgraphs = unless (null subgraphs) . warn $ resolveGraphFailureBundle subgraphs + partitionSubgraph (a, Nothing) = Left a + partitionSubgraph (_, Just b) = Right b -resolveGraphFailureBundle :: [(VSI.Locator, Maybe (Graphing VSI.Locator))] -> Text +resolveGraphFailureBundle :: [VSI.Locator] -> Text resolveGraphFailureBundle subgraphs = "Failed to resolve dependencies for the following FOSSA projects:\n\t" - <> intercalate "\n\t" (renderFailed subgraphs) + <> intercalate "\n\t" (fmap VSI.renderLocator subgraphs) <> "\n\n" - <> "You may not have access to the projects, or they may not exist (see the warnings below for details).\n" - <> "If desired you can use --experimental-skip-vsi-graph to skip resolving the dependencies of these projects." - where - renderFailed [] = [] - renderFailed ((a, b) : xs) = case b of - Just _ -> renderFailed xs - Nothing -> VSI.renderLocator a : renderFailed xs + <> "You may not have access to the projects, or they may not exist.\n" -- | Given a traverseable list and a monadic function that resolves them to b, traverse and zip the list into a pair of (a, b) traverseZipM :: (Traversable t, Applicative m) => (a -> m b) -> t a -> m (t (a, b)) traverseZipM f = traverse (\a -> (a,) <$> f a) +-- | Split the list into two mapped lists based on the predicate. +partitionMap :: (a -> Either b c) -> [a] -> ([b], [c]) +partitionMap split items = partitionEithers $ map split items + -- Pass through the list of skipped locators all the way here: -- we want to still record the direct dependency, we just don't want to resolve it. resolveSubgraph :: (Has FossaApiClient sig m, Has Diagnostics sig m) => VSI.SkipResolution -> VSI.Locator -> m (Maybe (Graphing VSI.Locator)) diff --git a/test/App/Fossa/VSI/IAT/ResolveSpec.hs b/test/App/Fossa/VSI/IAT/ResolveSpec.hs index df4de6e577..b3c5cf3579 100644 --- a/test/App/Fossa/VSI/IAT/ResolveSpec.hs +++ b/test/App/Fossa/VSI/IAT/ResolveSpec.hs @@ -10,7 +10,7 @@ import DepTypes (DepType (CustomType)) import Graphing qualified import Srclib.Converter (depTypeToFetcher) import Srclib.Types (SourceUserDefDep (..)) -import Test.Effect (expectFatal', it', shouldBe') +import Test.Effect (it', shouldBe') import Test.Hspec (Spec, describe) import Test.MockApi (fails, returnsOnce) @@ -47,17 +47,22 @@ spec = do maybeDeps <- resolveRevision package maybeDeps `shouldBe'` Just [dep1, dep2] describe "resolveGraph" $ do - it' "dies if resolving any subgraph fails to resolve" $ do + it' "resolves available subgraphs" $ do let package1 = testTopLevelLocator 1 package2 = testTopLevelLocator 2 dep1 = testLocator 11 dep2 = testLocator 12 skips = SkipResolution (Set.empty) + expectedGraph = + Graphing.directs [package1] + <> Graphing.edges [(package1, dep1), (package1, dep2)] -- Package1 is fine ResolveProjectDependencies package1 `returnsOnce` [dep1, dep2] -- Package2 has an error ResolveProjectDependencies package2 `fails` "Mock error" - expectFatal' $ resolveGraph [package1, package2] skips + -- The graph should resolve with the successful results. + graph <- resolveGraph [package1, package2] skips + graph `shouldBe'` expectedGraph it' "resolves dependencies not in the skip list" $ do let package1 = testTopLevelLocator 1 package2 = testTopLevelLocator 2