Repository: hasura/graphql-engine
File: server/src-lib/Hasura/Server/Version.hs (Haskell)

Code before:

-- | Lots of random things need access to the current version. It would be very convenient to define
-- @version :: 'Version'@ in this module and export it, and indeed, that’s what we used to do! But
-- that turns out to cause problems: the version is compiled into the executable via Template
-- Haskell, so the Pro codebase runs into awkward problems. Since the Pro codebase depends on this
-- code as a library, it has to do gymnastics to ensure that this library always gets recompiled in
-- order to use the updated version, and that’s really hacky.
--
-- A better solution is to explicitly plumb the version through to everything that needs it, but
-- that would be noisy, so as a compromise we use an implicit parameter. Since implicit parameters
-- are a little cumbersome, we hide the parameter itself behind this 'HasVersion' constraint,
-- 'currentVersion' can be used to access it, and 'withVersion' can be used to bring a version into
-- scope.
type HasVersion = ?version :: Version

currentVersion :: HasVersion => Version
currentVersion = ?version

withVersion :: Version -> (HasVersion => r) -> r
withVersion version x = let ?version = version in x

consoleVersion :: HasVersion => Text
consoleVersion = case currentVersion of
  VersionDev txt -> txt
  VersionRelease v -> case getReleaseChannel v of
    Nothing -> vMajMin
    Just c  -> "channel/" <> c <> "/" <> vMajMin
    where
      vMajMin = T.pack ("v" <> show (v ^. V.major) <> "." <> show (v ^. V.minor))
  where
    getReleaseChannel :: V.Version -> Maybe Text
    getReleaseChannel sv = case sv ^. V.release of
      []     -> Just "stable"
      (mr:_) -> case getTextFromId mr of
        Nothing -> Nothing
        Just r  -> if
          | "alpha" `T.isPrefixOf` r -> Just "alpha"
          | "beta" `T.isPrefixOf` r  -> Just "beta"
          | "rc" `T.isPrefixOf` r    -> Just "rc"
          | otherwise                -> Nothing

    getTextFromId :: V.Identifier -> Maybe Text
    getTextFromId i = Just i ^? (toTextualM . V._Textual)
      where
        toTextualM _ Nothing  = pure Nothing
        toTextualM f (Just a) = f a


Review comment (suggestion):
I am not entirely sure, but looks like in the previous implementation, when `getReleaseChannel v` returns `Nothing` it would return `rawVersion` which was defined as `"versioned/" <> version`.
Also, when the version was a dev version, `consoleVersion` returned `rawVersion`.

So shouldn't we prefix `txt` and `vMajMin` here with `"versioned/"` as well? Or am I missing something? To be honest, I don't really know this scheme. Looks like the console version here, reflects where the assets are stored. I think @shahidhk has better info on this and he can clarify if required.

Code after:

-- | Lots of random things need access to the current version. It would be very convenient to define
-- @version :: 'Version'@ in this module and export it, and indeed, that’s what we used to do! But
-- that turns out to cause problems: the version is compiled into the executable via Template
-- Haskell, so the Pro codebase runs into awkward problems. Since the Pro codebase depends on this
-- code as a library, it has to do gymnastics to ensure that this library always gets recompiled in
-- order to use the updated version, and that’s really hacky.
--
-- A better solution is to explicitly plumb the version through to everything that needs it, but
-- that would be noisy, so as a compromise we use an implicit parameter. Since implicit parameters
-- are a little cumbersome, we hide the parameter itself behind this 'HasVersion' constraint,
-- 'currentVersion' can be used to access it, and 'withVersion' can be used to bring a version into
-- scope.
type HasVersion = ?version :: Version

currentVersion :: HasVersion => Version
currentVersion = ?version

withVersion :: Version -> (HasVersion => r) -> r
withVersion version x = let ?version = version in x

-- | A version-based string used to form the CDN URL for fetching console assets.
consoleAssetsVersion :: HasVersion => Text
consoleAssetsVersion = case currentVersion of
  VersionDev txt -> "versioned/" <> txt
  VersionRelease v -> case getReleaseChannel v of
    Nothing -> "versioned/" <> vMajMin
    Just c  -> "channel/" <> c <> "/" <> vMajMin
    where
      vMajMin = T.pack ("v" <> show (v ^. V.major) <> "." <> show (v ^. V.minor))
  where
    getReleaseChannel :: V.Version -> Maybe Text
    getReleaseChannel sv = case sv ^. V.release of
      []     -> Just "stable"
      (mr:_) -> case getTextFromId mr of
        Nothing -> Nothing
        Just r  -> if
          | "alpha" `T.isPrefixOf` r -> Just "alpha"
          | "beta" `T.isPrefixOf` r  -> Just "beta"
          | "rc" `T.isPrefixOf` r    -> Just "rc"
          | otherwise                -> Nothing

    getTextFromId :: V.Identifier -> Maybe Text
    getTextFromId i = Just i ^? (toTextualM . V._Textual)
      where
        toTextualM _ Nothing  = pure Nothing
        toTextualM f (Just a) = f a