From 82af250762bf189e0e4980e38e617149a2cc7c1e Mon Sep 17 00:00:00 2001 From: Luca Ruperto Date: Wed, 17 Jun 2026 14:03:29 +0200 Subject: [PATCH 1/2] urlReachable: stub new function and call site --- src/GH.hs | 4 ++++ src/Update.hs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/GH.hs b/src/GH.hs index 7df2ae77..a04ed897 100644 --- a/src/GH.hs +++ b/src/GH.hs @@ -11,6 +11,7 @@ module GH authFromToken, checkExistingUpdatePR, closedAutoUpdateRefs, + urlReachable, compareUrl, latestVersion, pr, @@ -149,6 +150,9 @@ parseURLMaybe url = ) in url =~ regex +urlReachable :: Text -> IO Bool +urlReachable _ = pure True -- TODO + parseURL :: MonadIO m => Text -> ExceptT Text m URLParts parseURL url = tryJust ("GitHub: " <> url <> " is not a GitHub URL.") (parseURLMaybe url) diff --git a/src/Update.hs b/src/Update.hs index 64eb3337..89a8646a 100644 --- a/src/Update.hs +++ b/src/Update.hs @@ -253,6 +253,12 @@ updateAttrPath log mergeBase updateEnv@UpdateEnv {..} attrPath = do "The derivation has no 'version' attribute, so do not know how to figure out the version while doing an updateScript update" (not hasUpdateScript || isJust oldVerMay) + unless hasUpdateScript $ + when (T.isInfixOf oldVersion oldSrcUrl) do + let url = oldVersion `T.replace` newVersion $ oldSrcUrl + reachable <- liftIO $ GH.urlReachable url + unless reachable $ throwE ("The new url doesn't exist: " <> url) + -- One final filter Skiplist.content derivationContents From 5ab9e23fedf7ce1022cc07cfc13822e0f73510c0 Mon Sep 17 00:00:00 2001 From: Luca Ruperto Date: Wed, 17 Jun 2026 14:40:00 +0200 Subject: [PATCH 2/2] urlReachable: use Network.HTTP.Client to make a HEAD request to github --- src/GH.hs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/GH.hs b/src/GH.hs index a04ed897..425c7597 100644 --- a/src/GH.hs +++ b/src/GH.hs @@ -20,6 +20,7 @@ module GH where import Control.Applicative (liftA2, some) +import Control.Exception (try) import Data.Aeson (FromJSON) import Data.Bitraversable (bitraverse) import qualified Data.Text as T @@ -29,7 +30,8 @@ import qualified Data.Vector as V import qualified Git import qualified GitHub as GH import GitHub.Data.Name (Name (..)) -import Network.HTTP.Client (HttpException (..), HttpExceptionContent (..), responseStatus) +import Network.HTTP.Client +import Network.HTTP.Client.TLS (tlsManagerSettings) import Network.HTTP.Types.Status (statusCode) import OurPrelude import Text.Regex.Applicative.Text ((=~)) @@ -151,7 +153,18 @@ parseURLMaybe url = in url =~ regex urlReachable :: Text -> IO Bool -urlReachable _ = pure True -- TODO +urlReachable url = + case parseRequest $ T.unpack url of + Nothing -> pure False + Just req -> do + manager <- newManager tlsManagerSettings + res <- + try $ + (httpNoBody (req {method = "HEAD"}) manager) :: + IO (Either HttpException (Response ())) + case res of + Left _ -> pure False + Right resp -> pure $ statusCode (responseStatus resp) == 200 parseURL :: MonadIO m => Text -> ExceptT Text m URLParts parseURL url =