mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
server/ci: rework version baking, and cache dist-newstyle in CI
UPDATE: After testing in CI it turns out that the compile time Improvement is better than expected: even though we always have to recompile the OSS lib (due to Version.hs), downstream packages like Pro and multi-tenant can still benefit from some caching and avoid full recompilation. In the best case this takes us from 22 minutes to 13 minutes total. PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4104 GitOrigin-RevId: 76cbfc157064b33856e30f4c2b2ab2366f9c6089
This commit is contained in:
parent
dcd3ccb75b
commit
fdea752679
@ -148,6 +148,12 @@ MODE="$1"
|
||||
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd )" # ... https://stackoverflow.com/a/246128/176841
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# In CI we use the get version script to actually populate the version number
|
||||
# that will be compiled into the server. For local development we use this
|
||||
# magic number, which means we won't recompile unnecessarily. This number also
|
||||
# gets explicitly ignored in the version test in integration tests.
|
||||
echo '12345' > "$PROJECT_ROOT/server/CURRENT_VERSION"
|
||||
|
||||
# Use pyenv if available to set an appropriate python version that will work with pytests etc.
|
||||
if command -v pyenv >/dev/null; then
|
||||
# For now I guess use the greatest python3 >= 3.5
|
||||
|
@ -10,6 +10,22 @@ maintainer: vamshi@hasura.io
|
||||
copyright: Hasura Inc.
|
||||
category: Database
|
||||
build-type: Simple
|
||||
extra-source-files:
|
||||
-- We use TH to bake in the server’s version number at compile time. In order
|
||||
-- for recompilation detection to work correctly (especially in the presence
|
||||
-- of caching) we need to both communicate this data via a file (referenced in
|
||||
-- TH with addDependentFile) /and/ add that file to this section of the cabal
|
||||
-- file. See: https://github.com/haskell/cabal/issues/4746
|
||||
--
|
||||
-- This file is intentionally .gitignore'd
|
||||
CURRENT_VERSION
|
||||
-- These are files referenced by functions from 'file-embed' which uses
|
||||
-- addDependentFile internally and has the same issue as above:
|
||||
src-rsr/mysql_table_metadata.sql
|
||||
src-rsr/mssql_table_metadata.sql
|
||||
src-rsr/catalog_versions.txt
|
||||
src-rsr/catalog_version.txt
|
||||
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TemplateHaskellQuotes #-}
|
||||
|
||||
module Hasura.Server.Utils
|
||||
( APIVersion (..),
|
||||
@ -16,7 +16,6 @@ module Hasura.Server.Utils
|
||||
fmapL,
|
||||
generateFingerprint,
|
||||
getRequestHeader,
|
||||
getValFromEnvOrScript,
|
||||
gzipHeader,
|
||||
httpExceptToJSON,
|
||||
isReqUserId,
|
||||
@ -51,12 +50,10 @@ import Data.ByteString.Base16 qualified as Base16
|
||||
import Data.ByteString.Lazy qualified as BL
|
||||
import Data.CaseInsensitive qualified as CI
|
||||
import Data.Char
|
||||
import Data.FileEmbed (makeRelativeToProject)
|
||||
import Data.HashSet qualified as Set
|
||||
import Data.List.NonEmpty qualified as NE
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.Extended
|
||||
import Data.Text.IO qualified as TI
|
||||
import Data.Time
|
||||
import Data.UUID qualified as UUID
|
||||
import Data.UUID.V4 qualified as UUID
|
||||
@ -65,13 +62,9 @@ import Database.PG.Query qualified as Q
|
||||
import Hasura.Base.Instances ()
|
||||
import Hasura.Prelude
|
||||
import Language.Haskell.TH.Syntax (Q, TExp)
|
||||
import Language.Haskell.TH.Syntax qualified as TH
|
||||
import Network.HTTP.Client qualified as HC
|
||||
import Network.HTTP.Types qualified as HTTP
|
||||
import Network.Wreq qualified as Wreq
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
import System.Process
|
||||
import Text.Regex.TDFA qualified as TDFA
|
||||
import Text.Regex.TDFA.ReadRegex qualified as TDFA
|
||||
import Text.Regex.TDFA.TDFA qualified as TDFA
|
||||
@ -127,13 +120,12 @@ parseStringAsBool t
|
||||
++ show falseVals
|
||||
++ ". All values are case insensitive"
|
||||
|
||||
-- Get an env var during compile time
|
||||
getValFromEnvOrScript :: String -> FilePath -> Q (TExp String)
|
||||
getValFromEnvOrScript var file = do
|
||||
maybeVal <- TH.runIO $ lookupEnv var
|
||||
case maybeVal of
|
||||
Just val -> [||val||]
|
||||
Nothing -> runScript file
|
||||
{- NOTE: Something like this is not safe in the presence of caching. The only
|
||||
way for metaprogramming to depend on some external data and recompile
|
||||
properly is via addDependentFile and to include that file in the
|
||||
extra-source-files in the cabal file (see: https://github.com/haskell/cabal/issues/4746).
|
||||
Leaving this here commented in order to document that fact and also in case
|
||||
there's a way forward in the future.
|
||||
|
||||
-- Run a shell script during compile time
|
||||
runScript :: FilePath -> Q (TExp String)
|
||||
@ -151,6 +143,7 @@ runScript file = do
|
||||
++ " and with error : "
|
||||
++ stdErr
|
||||
[||stdOut||]
|
||||
-}
|
||||
|
||||
-- | Quotes a regex using Template Haskell so syntax errors can be reported at compile-time.
|
||||
quoteRegex :: TDFA.CompOption -> TDFA.ExecOption -> String -> Q (TExp TDFA.Regex)
|
||||
|
@ -7,13 +7,16 @@ module Hasura.Server.Version
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Exception
|
||||
import Control.Lens ((^.), (^?))
|
||||
import Data.Aeson (FromJSON (..), ToJSON (..))
|
||||
import Data.FileEmbed (makeRelativeToProject)
|
||||
import Data.SemVer qualified as V
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.Conversions (FromText (..), ToText (..))
|
||||
import Hasura.Prelude
|
||||
import Hasura.Server.Utils (getValFromEnvOrScript)
|
||||
import Language.Haskell.TH
|
||||
import Language.Haskell.TH.Syntax
|
||||
import Text.Regex.TDFA ((=~~))
|
||||
|
||||
data Version
|
||||
@ -42,7 +45,21 @@ currentVersion =
|
||||
fromText $
|
||||
T.dropWhileEnd (== '\n') $
|
||||
T.pack $
|
||||
$$(getValFromEnvOrScript "VERSION" "../scripts/get-version.sh")
|
||||
-- NOTE: This must work correctly in the presence of a caching! See
|
||||
-- graphql-engine.cabal (search for “CURRENT_VERSION”) for details
|
||||
-- about our approach here. We could use embedFile but want a nice
|
||||
-- error message
|
||||
$( do
|
||||
versionFileName <- makeRelativeToProject "CURRENT_VERSION"
|
||||
addDependentFile versionFileName
|
||||
let noFileErr =
|
||||
"\n==========================================================================="
|
||||
<> "\n>>> DEAR HASURIAN: The way we bake versions into the server has "
|
||||
<> "\n>>> changed; You'll need to run the following once in your repo to proceed: "
|
||||
<> "\n>>> $ echo 12345 > \"$(git rev-parse --show-toplevel)/server/CURRENT_VERSION\""
|
||||
<> "\n===========================================================================\n"
|
||||
runIO (readFile versionFileName `onException` error noFileErr) >>= stringE
|
||||
)
|
||||
|
||||
-- | A version-based string used to form the CDN URL for fetching console assets.
|
||||
consoleAssetsVersion :: Text
|
||||
|
@ -12,8 +12,12 @@ class TestServerVersion(object):
|
||||
assert resp.status_code == 200, resp
|
||||
my_json = resp.json()
|
||||
assert isinstance(my_json, dict), my_json
|
||||
|
||||
# The magic number here means we're compiling for local development and
|
||||
# this test can be ignored:
|
||||
if my_json['version'] != '12345':
|
||||
# The tree may be dirty because we're developing tests locally while
|
||||
# graphql-engine was built previously when tree was clean. If we're
|
||||
# modifying graphql-engine too then both of these will be tagged dirty,
|
||||
# since a rebuild would necessarily be forced:
|
||||
assert my_json['version'] in (hge_ctx.version, re.sub('-dirty$', '', hge_ctx.version)), my_json
|
||||
assert my_json['version'] in (hge_ctx.version, re.sub('-dirty$', '', hge_ctx.version)), my_json
|
||||
|
Loading…
Reference in New Issue
Block a user