mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Build js packages at code-generation time (#5171)
changelog_begin changelog_end
This commit is contained in:
parent
1a229ebb7b
commit
9351b7a7b9
@ -71,14 +71,19 @@ da_haskell_test(
|
||||
name = "integration-tests",
|
||||
timeout = "long",
|
||||
srcs = glob(["src/**/*.hs"]),
|
||||
args = [
|
||||
"$(location //:yarn)",
|
||||
"daml-types-not-available" if is_windows else "$(location //language-support/ts/daml-types:npm_package)",
|
||||
],
|
||||
data = [
|
||||
":integration-tests-mvn",
|
||||
"//release:sdk-release-tarball",
|
||||
"@local_jdk//:bin/java.exe" if is_windows else "@local_jdk//:bin/java",
|
||||
"//:yarn",
|
||||
"//compiler/damlc/tests:generate-simple-dalf",
|
||||
"@mvn_dev_env//:mvn",
|
||||
"@tar_dev_env//:tar",
|
||||
],
|
||||
] + ([] if is_windows else ["//language-support/ts/daml-types:npm_package"]),
|
||||
# I’m sure the mvn stuff will be flaky.
|
||||
flaky = True,
|
||||
hackage_deps = [
|
||||
|
@ -31,33 +31,43 @@ import Test.Main
|
||||
import Test.Tasty
|
||||
import Test.Tasty.HUnit
|
||||
import qualified Web.JWT as JWT
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
import qualified Data.HashMap.Strict as HMS
|
||||
import Data.Aeson
|
||||
|
||||
import DA.Directory
|
||||
import DA.Bazel.Runfiles
|
||||
import DA.Daml.Helper.Run
|
||||
import SdkVersion
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
withTempDir $ \tmpDir -> do
|
||||
main = do
|
||||
setEnv "TASTY_NUM_THREADS" "1" True
|
||||
-- We manipulate global state via the working directory and
|
||||
-- the environment so running tests in parallel will cause trouble.
|
||||
setEnv "TASTY_NUM_THREADS" "1" True
|
||||
yarn : damlTypesPath : args <- getArgs
|
||||
withTempDir $ \tmpDir -> do
|
||||
oldPath <- getSearchPath
|
||||
javaPath <- locateRunfiles "local_jdk/bin"
|
||||
mvnPath <- locateRunfiles "mvn_dev_env/bin"
|
||||
tarPath <- locateRunfiles "tar_dev_env/bin"
|
||||
yarnPath <- takeDirectory <$> locateRunfiles (mainWorkspace </> yarn)
|
||||
damlTypesDir <-
|
||||
if isWindows
|
||||
then pure damlTypesPath -- Not available.
|
||||
else locateRunfiles (mainWorkspace </> damlTypesPath)
|
||||
-- NOTE: `COMSPEC` env. variable on Windows points to cmd.exe, which is required to be present
|
||||
-- on the PATH as mvn.cmd executes cmd.exe
|
||||
mbComSpec <- getEnv "COMSPEC"
|
||||
let mbCmdDir = takeDirectory <$> mbComSpec
|
||||
let damlDir = tmpDir </> "daml"
|
||||
withEnv
|
||||
withArgs args (withEnv
|
||||
[ ("DAML_HOME", Just damlDir)
|
||||
, ("PATH", Just $ intercalate [searchPathSeparator] $ ((damlDir </> "bin") : tarPath : javaPath : mvnPath : oldPath) ++ maybeToList mbCmdDir)
|
||||
] $ defaultMain (tests damlDir tmpDir)
|
||||
, ("PATH", Just $ intercalate [searchPathSeparator] $ ((damlDir </> "bin") : tarPath : javaPath : mvnPath : yarnPath : oldPath) ++ maybeToList mbCmdDir)
|
||||
] $ defaultMain (tests damlDir tmpDir damlTypesDir))
|
||||
|
||||
tests :: FilePath -> FilePath -> TestTree
|
||||
tests damlDir tmpDir = testGroup "Integration tests"
|
||||
tests :: FilePath -> FilePath -> FilePath -> TestTree
|
||||
tests damlDir tmpDir damlTypesDir = testGroup "Integration tests"
|
||||
[ testCase "install" $ do
|
||||
releaseTarball <- locateRunfiles (mainWorkspace </> "release" </> "sdk-release-tarball.tar.gz")
|
||||
createDirectory tarballDir
|
||||
@ -78,7 +88,7 @@ tests damlDir tmpDir = testGroup "Integration tests"
|
||||
, quickstartTests quickstartDir mvnDir
|
||||
, cleanTests cleanDir
|
||||
, deployTest deployDir
|
||||
, codegenTests codegenDir
|
||||
, codegenTests codegenDir damlTypesDir
|
||||
]
|
||||
where quickstartDir = tmpDir </> "q-u-i-c-k-s-t-a-r-t"
|
||||
cleanDir = tmpDir </> "clean"
|
||||
@ -474,12 +484,15 @@ cleanTests baseDir = testGroup "daml clean"
|
||||
]
|
||||
|
||||
-- | Check we can generate language bindings.
|
||||
codegenTests :: FilePath -> TestTree
|
||||
codegenTests codegenDir = testGroup "daml codegen"
|
||||
[ codegenTestFor "ts" Nothing
|
||||
, codegenTestFor "java" Nothing
|
||||
codegenTests :: FilePath -> FilePath -> TestTree
|
||||
codegenTests codegenDir damlTypes = testGroup "daml codegen" (
|
||||
[ codegenTestFor "java" Nothing
|
||||
, codegenTestFor "scala" (Just "com.cookiemonster.nomnomnom")
|
||||
]
|
||||
] ++
|
||||
-- The 'daml-types' NPM package is not available on Windows which
|
||||
-- is required by 'daml2ts'.
|
||||
[ codegenTestFor "ts" Nothing | not isWindows ]
|
||||
)
|
||||
where
|
||||
codegenTestFor :: String -> Maybe String -> TestTree
|
||||
codegenTestFor lang namespace =
|
||||
@ -490,8 +503,22 @@ codegenTests codegenDir = testGroup "daml codegen"
|
||||
callCommandQuiet $ unwords ["daml new", projectDir, "skeleton"]
|
||||
withCurrentDirectory projectDir $ do
|
||||
callCommandQuiet "daml build"
|
||||
let darFile = projectDir</> ".daml/dist/proj-" ++ lang ++ "-0.0.1.dar"
|
||||
outDir = projectDir</> "generated" </> lang
|
||||
let darFile = projectDir </> ".daml/dist/proj-" ++ lang ++ "-0.0.1.dar"
|
||||
outDir = projectDir </> "generated" </> lang
|
||||
when (lang == "ts") $ do
|
||||
createDirectoryIfMissing True "generated"
|
||||
withCurrentDirectory "generated" $ do
|
||||
-- SDK version is 0.0.0; daml2ts needs
|
||||
-- 'daml-types' to be here in the filesystem...
|
||||
copyDirectory damlTypes "daml-types"
|
||||
BSL.writeFile "package.json" $ encode (
|
||||
-- ... and this package.json so it can find it.
|
||||
object
|
||||
[ "private" .= True
|
||||
, "workspaces" .= [T.pack lang]
|
||||
, "resolutions" .= HMS.fromList ([("@daml/types", "file:daml-types")] :: [(T.Text, T.Text)])
|
||||
]
|
||||
)
|
||||
callCommandQuiet $
|
||||
unwords [ "daml", "codegen", lang
|
||||
, darFile ++ maybe "" ("=" ++) namespace
|
||||
|
@ -21,7 +21,7 @@ Usage
|
||||
|
||||
``daml2ts`` is invoked via the DAML SDK assistant.
|
||||
|
||||
In outline, the command to generate TypeScript from DAML is ``daml codegen ts DAR -o OUTDIR –main-package-name=PACKAGE`` where ``DAR`` is the path to a DAR file (generated via ``daml build``), ``OUTDIR`` is a directory where you want the TypeScript to be written and ``PACKAGE`` is a desired TypeScript package name.
|
||||
In outline, the command to generate TypeScript from DAML is ``daml codegen ts DAR -o OUTDIR`` where ``DAR`` is the path to a DAR file (generated via ``daml build``), ``OUTDIR`` is a directory where you want the TypeScript to be written and ``PACKAGE`` is a desired TypeScript package name.
|
||||
|
||||
Here's a complete example that generates TypeScript from a project produced from the standard "skeleton" template.
|
||||
|
||||
@ -31,15 +31,15 @@ Here's a complete example that generates TypeScript from a project produced from
|
||||
daml new my-proj skeleton # Create a new project based off the skeleton template
|
||||
cd my-proj # Enter the newly created project directory
|
||||
daml build # Compile the project's DAML files into a DAR
|
||||
daml codegen ts .daml/dist/my-proj-0.0.1.dar -o generated/ts --main-package-name=my-proj # Generate Typescript from the DAR
|
||||
daml codegen ts .daml/dist/my-proj-0.0.1.dar -o daml2ts # Generate script bindings from the DAR
|
||||
|
||||
- On execution of these commands:
|
||||
|
||||
- The directory ``my-proj/generated/ts`` contains the generated TypeScript source files;
|
||||
- The directory ``my-proj/daml2ts`` contains generated TypeScript and Javascript artifacts;
|
||||
- The files are arranged into directories;
|
||||
- One of those directories will be named as per the ``PACKAGE`` argument and will contain the TypeScript definitions corresponding to the DAML files in the project;
|
||||
- For example, ``generated/ts/my-proj/Main.ts`` contains the TypeScript definitions for ``daml/Main.daml``;
|
||||
- The remaining directories contain supporting TypeScript corresponding to modules of the DAML standard library;
|
||||
- One of those directories will be named as per the ``PACKAGE`` argument and will contain the definitions corresponding to the DAML files in the project;
|
||||
- For example, ``generated/ts/my-proj/Main.ts`` contains the definitions for ``daml/Main.daml``;
|
||||
- The remaining directories correspond to modules of the DAML standard library;
|
||||
- Those directories have numeric names (the names are hashes of the DAML-LF package they are derived from).
|
||||
|
||||
To get a quickstart idea of how to use what has been generated, you may wish to jump to the `Templates and choices`_ section and return to the reference material that follows as needed.
|
||||
|
@ -19,6 +19,7 @@ da_haskell_binary(
|
||||
"hashable",
|
||||
"lens",
|
||||
"optparse-applicative",
|
||||
"process",
|
||||
"text",
|
||||
"unordered-containers",
|
||||
"zip-archive",
|
||||
|
@ -3,6 +3,7 @@
|
||||
{-# LANGUAGE DerivingStrategies #-}
|
||||
module TsCodeGenMain (main) where
|
||||
|
||||
import DA.Directory
|
||||
import qualified DA.Daml.LF.Proto3.Archive as Archive
|
||||
import qualified DA.Daml.LF.Reader as DAR
|
||||
import qualified DA.Pretty
|
||||
@ -20,7 +21,6 @@ import Data.Aeson hiding (Options)
|
||||
import Data.Aeson.Encode.Pretty
|
||||
import Data.Hashable
|
||||
|
||||
import Control.Exception
|
||||
import Control.Monad.Extra
|
||||
import DA.Daml.LF.Ast
|
||||
import DA.Daml.LF.Ast.Optics
|
||||
@ -30,11 +30,12 @@ import Data.Graph
|
||||
import Data.Maybe
|
||||
import Data.Bifoldable
|
||||
import Options.Applicative
|
||||
import System.IO.Error
|
||||
import System.Directory
|
||||
import System.FilePath hiding ((<.>), (</>))
|
||||
import System.FilePath.Posix((</>)) -- Make sure we generate / on all platforms.
|
||||
import qualified System.FilePath as FP
|
||||
import System.Process
|
||||
import System.Exit
|
||||
|
||||
import DA.Daml.Project.Consts
|
||||
import DA.Daml.Project.Types
|
||||
@ -54,10 +55,7 @@ configConsts sdkVersion = ConfigConsts
|
||||
, (NpmPackageName "@daml/types", NpmPackageVersion sdkVersion)
|
||||
]
|
||||
, pkgDevDependencies = HMS.fromList
|
||||
[ (NpmPackageName "@typescript-eslint/eslint-plugin", NpmPackageVersion "2.11.0")
|
||||
, (NpmPackageName "@typescript-eslint/parser", NpmPackageVersion "2.11.0")
|
||||
, (NpmPackageName "eslint", NpmPackageVersion "^6.7.2")
|
||||
, (NpmPackageName "typescript", NpmPackageVersion "~3.7.3")
|
||||
[ (NpmPackageName "typescript", NpmPackageVersion "~3.7.3")
|
||||
]
|
||||
, pkgScripts = HMS.fromList
|
||||
[ (ScriptName "build", Script "tsc")
|
||||
@ -80,7 +78,7 @@ newtype Script = Script {unScript :: T.Text}
|
||||
data Options = Options
|
||||
{ optInputDars :: [FilePath]
|
||||
, optOutputDir :: FilePath
|
||||
, optInputPackageJson :: FilePath
|
||||
, optInputPackageJson :: Maybe FilePath -- Deprecated.
|
||||
, optScope :: Scope -- Defaults to 'daml.js'.
|
||||
}
|
||||
|
||||
@ -95,12 +93,11 @@ optionsParser = Options
|
||||
<> metavar "DIR"
|
||||
<> help "Output directory for the generated packages"
|
||||
)
|
||||
<*> strOption
|
||||
<*> optional (strOption
|
||||
( short 'p'
|
||||
<> metavar "PACKAGE-JSON"
|
||||
<> value "package.json"
|
||||
<> help "Path to a 'package.json' to update (or create if missing)"
|
||||
)
|
||||
<> help "This flag is deprecated and ignored"
|
||||
))
|
||||
<*> (Scope . ("@" <>) <$> strOption
|
||||
( short 's'
|
||||
<> metavar "SCOPE"
|
||||
@ -159,6 +156,8 @@ mergePackageMap ps = foldM merge Map.empty ps
|
||||
main :: IO ()
|
||||
main = do
|
||||
opts@Options{..} <- execParser optionsParserInfo
|
||||
when (isJust optInputPackageJson) $
|
||||
putStrLn "WARNING: Use of the flag '-p' is deprecated. This flag is ignored."
|
||||
sdkVersionOrErr <- DATypes.parseVersion . T.pack . fromMaybe "0.0.0" <$> getSdkVersionMaybe
|
||||
sdkVersion <- case sdkVersionOrErr of
|
||||
Left _ -> fail "Invalid SDK version"
|
||||
@ -177,13 +176,13 @@ main = do
|
||||
Just pkgName -> unPackageName pkgName <> " (hash: " <> id <> ")"
|
||||
T.putStrLn $ "Generating " <> pkgDesc
|
||||
daml2ts Daml2TsParams{..}
|
||||
setupWorkspace optInputPackageJson optOutputDir dependencies
|
||||
buildPackages sdkVersion optScope optOutputDir dependencies
|
||||
|
||||
packageNameText :: PackageId -> Maybe PackageName -> T.Text
|
||||
packageNameText pkgId mbPkgIdent = maybe (unPackageId pkgId) unPackageName mbPkgIdent
|
||||
|
||||
newtype Scope = Scope T.Text
|
||||
newtype Dependency = Dependency {unDependency :: T.Text} deriving (Eq, Ord)
|
||||
newtype Scope = Scope {unScope :: T.Text}
|
||||
newtype Dependency = Dependency {unDependency :: T.Text} deriving (Eq, Ord)
|
||||
|
||||
data Daml2TsParams = Daml2TsParams
|
||||
{ opts :: Options -- cli args
|
||||
@ -698,67 +697,47 @@ writePackageJson packageDir sdkVersion (Scope scope) depends =
|
||||
, "main" .= ("lib/index.js" :: T.Text)
|
||||
, "types" .= ("lib/index.d.ts" :: T.Text)
|
||||
, "description" .= ("Generated by daml2ts" :: T.Text)
|
||||
, "dependencies" .= (pkgDependencies config <> dependencies)
|
||||
, "devDependencies" .= pkgDevDependencies config
|
||||
, "dependencies" .= dependencies
|
||||
, "scripts" .= pkgScripts config
|
||||
]
|
||||
where
|
||||
config = configConsts sdkVersion
|
||||
|
||||
-- This type describes the format of a "top-level" 'package.json'. We
|
||||
-- expect such files to have the format
|
||||
-- {
|
||||
-- "workspaces: [
|
||||
-- "path/to/foo",
|
||||
-- "path/to/bar",
|
||||
-- ...
|
||||
-- ],
|
||||
-- ... perhaps other stuff ...
|
||||
-- }
|
||||
|
||||
data PackageJson = PackageJson
|
||||
{ workspaces :: [T.Text]
|
||||
, otherFields :: Object
|
||||
}
|
||||
deriving Show
|
||||
instance Semigroup PackageJson where
|
||||
l <> r = PackageJson (workspaces l <> workspaces r) (otherFields l <> otherFields r)
|
||||
instance Monoid PackageJson where
|
||||
mempty = PackageJson mempty mempty
|
||||
instance FromJSON PackageJson where
|
||||
parseJSON (Object v) = PackageJson
|
||||
<$> v .: "workspaces"
|
||||
<*> pure (HMS.delete "workspaces" v)
|
||||
parseJSON _ = mzero
|
||||
instance ToJSON PackageJson where
|
||||
toJSON PackageJson{..} = Object (HMS.insert "workspaces" (toJSON workspaces) otherFields)
|
||||
|
||||
-- Read the provided 'package.json'; transform it to include the
|
||||
-- provided workspaces; write it back to disk.
|
||||
setupWorkspace :: FilePath -> FilePath -> [(T.Text, [Dependency])] -> IO ()
|
||||
setupWorkspace optInputPackageJson optOutputDir dependencies = do
|
||||
buildPackages :: SdkVersion -> Scope -> FilePath -> [(T.Text, [Dependency])] -> IO ()
|
||||
buildPackages sdkVersion optScope optOutputDir dependencies = do
|
||||
let (g, nodeFromVertex) = graphFromEdges'
|
||||
(map (\(a, ds) -> (a, a, map unDependency ds)) dependencies)
|
||||
ps = map (fst3 . nodeFromVertex) $ reverse (topSort g)
|
||||
-- Topologically order our packages.
|
||||
outBaseDir = T.pack $ takeFileName optOutputDir
|
||||
-- The leaf directory of the output directory (e.g. often 'daml2ts').
|
||||
let ourWorkspaces = map ((outBaseDir <> "/") <>) ps
|
||||
mbBytes <- catchJust (guard . isDoesNotExistError)
|
||||
(Just <$> BSL.readFile optInputPackageJson) (const $ pure Nothing)
|
||||
packageJson <- case mbBytes of
|
||||
Nothing -> pure mempty
|
||||
Just bytes ->
|
||||
case eitherDecode @PackageJson bytes of
|
||||
Left msg -> fail $ "Error : '" <> optInputPackageJson <> "' : " <> msg
|
||||
Right packageJson -> pure packageJson
|
||||
transformAndWrite ourWorkspaces outBaseDir packageJson
|
||||
pkgs = map (T.unpack . fst3 . nodeFromVertex) $ reverse (topSort g)
|
||||
withCurrentDirectory optOutputDir $ do
|
||||
BSL.writeFile "package.json" $ encodePretty packageJson
|
||||
callProcessSilent "yarn" ["install", "--pure-lockfile"]
|
||||
createDirectoryIfMissing True $ "node_modules" </> scope
|
||||
mapM_ build pkgs
|
||||
removeFile "package.json" -- Any subsequent runs will regenerate it.
|
||||
-- We don't remove 'node_modules' : subsequent runs can benefit from caching.
|
||||
where
|
||||
transformAndWrite :: [T.Text] -> T.Text -> PackageJson -> IO ()
|
||||
transformAndWrite ourWorkspaces outBaseDir packageJson = do
|
||||
let keepWorkspaces = filter (not . T.isPrefixOf outBaseDir) $ workspaces packageJson
|
||||
-- Old versions of our packages should be removed.
|
||||
allWorkspaces = ourWorkspaces ++ keepWorkspaces
|
||||
-- Our packages need to come before any other existing packages.
|
||||
BSL.writeFile optInputPackageJson $ encodePretty packageJson{workspaces=allWorkspaces}
|
||||
putStrLn $ "'" <> optInputPackageJson <> "' created or updated."
|
||||
packageJson :: Value
|
||||
packageJson = object
|
||||
[ "name" .= ("daml2ts" :: T.Text)
|
||||
, "version" .= version
|
||||
, "dependencies" .= pkgDependencies config
|
||||
, "devDependencies" .= pkgDevDependencies config
|
||||
]
|
||||
|
||||
scope = T.unpack $ unScope optScope
|
||||
config = configConsts version
|
||||
version = versionToText sdkVersion
|
||||
|
||||
build :: String -> IO ()
|
||||
build pkg = do
|
||||
putStrLn $ "Building " <> pkg
|
||||
callProcessSilent "yarn" ["run", "tsc", "--project", pkg </> "tsconfig.json"]
|
||||
copyDirectory pkg $ "node_modules" </> scope </> pkg
|
||||
|
||||
callProcessSilent :: FilePath -> [String] -> IO ()
|
||||
callProcessSilent cmd args = do
|
||||
(exitCode, _, err) <- readProcessWithExitCode cmd args ""
|
||||
unless (exitCode == ExitSuccess) $ do
|
||||
putStrLn $ "Failure: Command \"" <> cmd <> " " <> unwords args <> "\" exited with " <> show exitCode
|
||||
putStrLn err
|
||||
exitFailure
|
||||
|
@ -30,7 +30,7 @@ daml_compile(
|
||||
# - 'ts/codegen/tests/daml/*'
|
||||
# The DAML that goes into the DAR ('build-and-lint-1.0.0.dar');
|
||||
# - 'ts/codegen/tests/ts/*'
|
||||
# A skeleton yarn workspaces root containing a TypeScript package
|
||||
# A yarn workspaces root containing a single TypeScript package
|
||||
# 'build-and-lint-test' which houses the test driver 'test.ts'.
|
||||
#
|
||||
# 'build-and-lint' creates a temp directory ('root' say), and uses the
|
||||
@ -43,10 +43,10 @@ daml_compile(
|
||||
# __tests__/
|
||||
# test.ts
|
||||
# daml2ts/
|
||||
# build-and-lint-1.0.0/ -- The TypeScript generated from 'build-and-lint-1.0.0.dar'
|
||||
# build-and-lint-1.0.0/ -- The artifacts generated of 'build-and-lint-1.0.0.dar'
|
||||
# 057eed/
|
||||
# ...
|
||||
# package.json -- Enumeration of the workspaces : build-and-lint, daml2ts/build-and-lint-1.0.0, ...
|
||||
# package.json -- Singleton package workspace : build-and-lint-test
|
||||
# node_modules/
|
||||
# @daml/
|
||||
# types/
|
||||
@ -54,8 +54,8 @@ daml_compile(
|
||||
# ...
|
||||
#
|
||||
# In more detail, the actions of 'build-and-lint' are to:
|
||||
# - Invoke 'daml2ts' on 'build-and-lint-1.0.0.dar' produce TypeScript bindings (
|
||||
# in the 'daml2ts' directory);
|
||||
# - Invoke 'daml2ts' on 'build-and-lint-1.0.0.dar' to produce bindings
|
||||
# (in the 'daml2ts' directory);
|
||||
# - Invoke from 'root':
|
||||
# - 'yarn workspaces run install';
|
||||
# - 'yarn workspaces run build';
|
||||
@ -136,12 +136,16 @@ da_haskell_test(
|
||||
"@davl//:released/davl-v5.dar",
|
||||
],
|
||||
hackage_deps = [
|
||||
"aeson",
|
||||
"base",
|
||||
"bytestring",
|
||||
"extra",
|
||||
"filepath",
|
||||
"process",
|
||||
"tasty",
|
||||
"tasty-hunit",
|
||||
"text",
|
||||
"unordered-containers",
|
||||
],
|
||||
main_function = "DA.Test.Daml2Ts.main",
|
||||
src_strip_prefix = "src",
|
||||
|
@ -57,11 +57,14 @@ cp -rL $DAML_LEDGER/* $TMP_DAML_LEDGER
|
||||
|
||||
cd $TMP_DIR
|
||||
|
||||
$DAML2TS -o daml2ts $DAR -p $TMP_DIR/package.json
|
||||
$YARN install --frozen-lockfile
|
||||
$YARN workspaces run build
|
||||
$YARN workspaces run lint
|
||||
# Call daml2ts.
|
||||
PATH=`dirname $YARN`:$PATH $DAML2TS -o daml2ts $DAR
|
||||
|
||||
# The previous step provides all the daml2ts Javascript needed by the
|
||||
# build-and-lint-test workspace.
|
||||
$YARN install --pure-lockfile > /dev/null 2>&1
|
||||
$YARN workspaces run build # Build it.
|
||||
$YARN workspaces run lint # No great value in this but nonetheless, lint it.
|
||||
# Invoke 'yarn test' in the 'build-and-lint-test' package
|
||||
# directory. Control is thereby passed to
|
||||
# 'language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts'.
|
||||
|
@ -15,18 +15,28 @@ import qualified DA.Daml.LF.Ast.Version as LF
|
||||
import DA.Directory
|
||||
import Data.Maybe
|
||||
import Data.List.Extra
|
||||
import qualified Data.Text.Extended as T
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
import qualified Data.HashMap.Strict as HMS
|
||||
import Data.Aeson
|
||||
import Test.Tasty
|
||||
import Test.Tasty.HUnit
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
setEnv "TASTY_NUM_THREADS" "1" True
|
||||
-- We manipulate global state via the working directory and
|
||||
-- the environment so running tests in parallel will cause trouble.
|
||||
yarnPath : damlTypesPath : args <- getArgs
|
||||
damlc <- locateRunfiles (mainWorkspace </> "compiler" </> "damlc" </> exe "damlc")
|
||||
daml2ts <- locateRunfiles (mainWorkspace </> "language-support" </> "ts" </> "codegen" </> exe "daml2ts")
|
||||
davl <- locateRunfiles ("davl" </> "released")
|
||||
yarnPath : damlTypesPath : args <- getArgs
|
||||
yarn <- locateRunfiles (mainWorkspace </> yarnPath)
|
||||
damlTypes <- (</> damlTypesPath) <$> getCurrentDirectory
|
||||
damlTypes <- locateRunfiles (mainWorkspace </> damlTypesPath)
|
||||
davl <- locateRunfiles ("davl" </> "released")
|
||||
-- TODO (SF,2020-03-24): Factor out 'withEnv' from
|
||||
-- 'DA/DamlAssistant/Tests.hs' into a library function and use it here.
|
||||
oldPath <- getSearchPath
|
||||
setEnv "PATH" (intercalate [searchPathSeparator] $ takeDirectory yarn : oldPath) True
|
||||
withArgs args (defaultMain $ tests damlTypes yarn damlc daml2ts davl)
|
||||
|
||||
-- It may help to keep in mind for the following tests, this quick
|
||||
@ -85,8 +95,8 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
|
||||
step "daml build..."
|
||||
buildProject ["-o", ".daml" </> "dist" </> "elmo-1.0.dar"]
|
||||
step "daml2ts..."
|
||||
setupWorkspace
|
||||
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, elmoDar] ++ ["-o", daml2tsDir, "-p", here </> "package.json"]) ""
|
||||
copyDirectory damlTypes "daml-types"
|
||||
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, elmoDar] ++ ["-o", daml2tsDir]) ""
|
||||
assertBool "A duplicate name for different packages error was expected." (exitCode /= ExitSuccess && isJust (stripInfix "Duplicate name 'grover-1.0' for different packages detected" err))
|
||||
|
||||
, testCaseSteps "Different name, same package test" $ \step -> withTempDir $ \here -> do
|
||||
@ -133,47 +143,18 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
|
||||
buildProject []
|
||||
withCurrentDirectory here $ do
|
||||
step "daml2ts..."
|
||||
setupWorkspace
|
||||
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, superGroverDar] ++ ["-o", daml2tsDir, "-p", here </> "package.json"]) ""
|
||||
copyDirectory damlTypes "daml-types"
|
||||
writePackageJson
|
||||
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, superGroverDar] ++ ["-o", daml2tsDir]) ""
|
||||
assertBool "A different names for same package error was expected." (exitCode /= ExitSuccess && isJust (stripInfix "Different names ('grover-1.0' and 'super-grover-1.0') for the same package detected" err))
|
||||
|
||||
, testCaseSteps "Bad package.json test" $ \step -> withTempDir $ \here -> do
|
||||
let grover = here </> "grover"
|
||||
groverDaml = grover </> "daml"
|
||||
daml2tsDir = here </> "daml2ts"
|
||||
groverDar = grover </> ".daml" </> "dist" </> "grover-1.0.dar"
|
||||
createDirectoryIfMissing True groverDaml
|
||||
withCurrentDirectory grover $ do
|
||||
writeFileUTF8 (groverDaml </> "Grover.daml") $ unlines
|
||||
[ "module Grover where"
|
||||
, "template Grover"
|
||||
, " with puppeteer : Party"
|
||||
, " where"
|
||||
, " signatory puppeteer"
|
||||
, " choice Grover_GoSuper: ContractId Grover"
|
||||
, " controller puppeteer"
|
||||
, " do"
|
||||
, " return self"
|
||||
]
|
||||
writeDamlYaml "grover" ["Grover"] ["daml-prim", "daml-stdlib"] Nothing
|
||||
step "daml build..."
|
||||
buildProject []
|
||||
withCurrentDirectory here $ do
|
||||
step "daml2ts..."
|
||||
setupWorkspace
|
||||
writeFileUTF8 (here </> "package.json") .
|
||||
replace " \"@daml/types\": \"file:daml-types\""
|
||||
" \"@daml/types\": \"file:daml-types\","
|
||||
=<< readFileUTF8' (here </> "package.json")
|
||||
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar] ++ ["-o", daml2tsDir]) ""
|
||||
assertBool "An error decoding package.json was expected." (exitCode /= ExitSuccess && isJust (stripInfix "'package.json' : Error in $: Failed reading: satisfy. Expecting object value)" err))
|
||||
|
||||
, testCaseSteps "Same package, same name test" $ \step -> withTempDir $ \here -> do
|
||||
let grover = here </> "grover"
|
||||
groverDaml = grover </> "daml"
|
||||
daml2tsDir = here </> "daml2ts"
|
||||
groverTs = daml2tsDir </> "grover-1.0"
|
||||
groverTsSrc = groverTs </> "src"
|
||||
groverTsLib = groverTs </> "lib"
|
||||
groverDar = grover </> ".daml" </> "dist" </> "grover-1.0.dar"
|
||||
createDirectoryIfMissing True groverDaml
|
||||
withCurrentDirectory grover $ do
|
||||
@ -193,55 +174,65 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
|
||||
buildProject []
|
||||
withCurrentDirectory here $ do
|
||||
step "daml2ts..."
|
||||
setupWorkspace
|
||||
daml2tsProject [groverDar, groverDar] daml2tsDir (here </> "package.json")
|
||||
writePackageJson
|
||||
copyDirectory damlTypes "daml-types"
|
||||
daml2tsProject [groverDar, groverDar] daml2tsDir
|
||||
assertFileExists (groverTsSrc </> "Grover.ts")
|
||||
assertFileExists (groverTsLib </> "Grover.js")
|
||||
assertFileExists (groverTsLib </> "Grover.d.ts")
|
||||
assertFileExists (groverTsSrc </> "packageId.ts")
|
||||
assertFileExists (groverTsLib </> "packageId.js")
|
||||
assertFileExists (groverTsLib </> "packageId.d.ts")
|
||||
|
||||
, testCaseSteps "DAVL test" $ \step -> withTempDir $ \here -> do
|
||||
let daml2tsDir = here </> "daml2ts"
|
||||
withCurrentDirectory here $ do
|
||||
copyDirectory damlTypes "daml-types"
|
||||
step "daml2ts..."
|
||||
-- Call daml2ts once without a 'package.json'.
|
||||
writePackageJson
|
||||
callProcessSilent daml2ts $
|
||||
[ davl </> "davl-v4.dar"
|
||||
, davl </> "davl-v5.dar"
|
||||
, davl </> "davl-upgrade-v4-v5.dar" ] ++
|
||||
["-o", daml2tsDir]
|
||||
assertFileExists (here </> "package.json")
|
||||
-- Overwrite the 'package.json' that daml2ts generated because
|
||||
-- we need to adjust module resolution for @daml/types and
|
||||
-- @daml/ledger.
|
||||
setupWorkspace
|
||||
-- Call daml2ts again which will this time update 'package.json'.
|
||||
callProcessSilent daml2ts $
|
||||
[ davl </> "davl-v4.dar"
|
||||
, davl </> "davl-v5.dar"
|
||||
, davl </> "davl-upgrade-v4-v5.dar" ] ++
|
||||
["-o", daml2tsDir] -- There's no need to pass '-p
|
||||
-- here/package.json' but we could and it would mean the same.
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "src" </> "DAVL.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "src" </> "DAVL.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "src" </> "Upgrade.ts")
|
||||
step "yarn install..."
|
||||
yarnProject ["install"]
|
||||
step "yarn workspaces run build..."
|
||||
yarnProject ["workspaces", "run", "build"]
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "lib" </> "DAVL.js")
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "lib" </> "DAVL.d.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "src" </> "DAVL.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "lib" </> "DAVL.js")
|
||||
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "lib" </> "DAVL.d.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "src" </> "Upgrade.ts")
|
||||
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "lib" </> "Upgrade.js")
|
||||
step "yarn workspaces run lint..."
|
||||
yarnProject ["workspaces", "run", "lint"]
|
||||
]
|
||||
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "lib" </> "Upgrade.d.ts")
|
||||
step "eslint..."
|
||||
withCurrentDirectory daml2tsDir $ do
|
||||
pkgs <- (\\ ["package.json", "node_modules"]) <$> listDirectory daml2tsDir
|
||||
BSL.writeFile "package.json" $ encode (
|
||||
object
|
||||
[ "private" .= True
|
||||
, "devDependencies" .= HMS.fromList
|
||||
([ ("eslint", "^6.7.2")
|
||||
, ("@typescript-eslint/eslint-plugin", "2.11.0")
|
||||
, ("@typescript-eslint/parser", "2.11.0")
|
||||
] :: [(T.Text, T.Text)]
|
||||
)
|
||||
, "dependencies" .= HMS.fromList
|
||||
([ ("@daml/types", "file:../daml-types")
|
||||
, ("@mojotech/json-type-validation", "^3.1.0")
|
||||
] :: [(T.Text, T.Text)])
|
||||
, "workspaces" .= pkgs
|
||||
, "name" .= ("daml2ts" :: T.Text)
|
||||
, "version" .= ("0.0.0" :: T.Text)
|
||||
])
|
||||
callProcessSilent yarn ["install", "--pure-lockfile"]
|
||||
callProcessSilent yarn ["workspaces", "run", "lint"]
|
||||
]
|
||||
where
|
||||
buildProject :: [String] -> IO ()
|
||||
buildProject args = callProcessSilent damlc (["build"] ++ args)
|
||||
|
||||
daml2tsProject :: [FilePath] -> FilePath -> FilePath -> IO ()
|
||||
daml2tsProject dars outDir packageJson = callProcessSilent daml2ts $ dars ++ ["-o", outDir, "-p", packageJson]
|
||||
|
||||
yarnProject :: [String] -> IO ()
|
||||
yarnProject args = callProcessSilent yarn args
|
||||
daml2tsProject :: [FilePath] -> FilePath -> IO ()
|
||||
daml2tsProject dars outDir = callProcessSilent daml2ts $ dars ++ ["-o", outDir]
|
||||
|
||||
callProcessSilent :: FilePath -> [String] -> IO ()
|
||||
callProcessSilent cmd args = do
|
||||
@ -252,19 +243,6 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
|
||||
hPutStrLn stderr $ unlines ["stderr:", err]
|
||||
exitFailure
|
||||
|
||||
setupWorkspace :: IO ()
|
||||
setupWorkspace = do
|
||||
copyDirectory damlTypes "daml-types"
|
||||
writeFileUTF8 "package.json" $ unlines
|
||||
[ "{"
|
||||
, " \"private\": true,"
|
||||
, " \"workspaces\": [],"
|
||||
, " \"resolutions\": {"
|
||||
, " \"@daml/types\": \"file:daml-types\""
|
||||
, " }"
|
||||
, "}"
|
||||
]
|
||||
|
||||
writeDamlYaml :: String -> [String] -> [String] -> Maybe LF.Version -> IO ()
|
||||
writeDamlYaml mainPackageName exposedModules dependencies mbLfVersion =
|
||||
writeFileUTF8 "daml.yaml" $ unlines $
|
||||
@ -278,5 +256,14 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
|
||||
[" - " ++ dependency | dependency <- dependencies] ++
|
||||
["build-options: [--target=" <> LF.renderVersion ver <> "]" | Just ver <- [mbLfVersion]]
|
||||
|
||||
writePackageJson :: IO ()
|
||||
writePackageJson = BSL.writeFile "package.json" $ encode packageJson
|
||||
where
|
||||
packageJson = object
|
||||
[ "private" .= True
|
||||
, "workspaces" .= (["daml2ts"] :: [T.Text])
|
||||
, "resolutions" .= HMS.fromList ([("@daml/types", "file:daml-types")] :: [(T.Text, T.Text)])
|
||||
]
|
||||
|
||||
assertFileExists :: FilePath -> IO ()
|
||||
assertFileExists file = doesFileExist file >>= assertBool (file ++ " was not created")
|
||||
|
@ -5,8 +5,7 @@
|
||||
"description": "Tests exercising '@daml.js/build-and-lint-1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@daml/ledger": "0.0.0",
|
||||
"@daml/types": "0.0.0",
|
||||
"@daml/ledger": "file:../daml-ledger",
|
||||
"@daml.js/build-and-lint-1.0.0": "file:../daml2ts/build-and-lint-1.0.0",
|
||||
"p-event": "^4.1.0"
|
||||
},
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"build-and-lint-test"
|
||||
"build-and-lint-test",
|
||||
"daml2ts"
|
||||
],
|
||||
"resolutions": {
|
||||
"@daml/types": "file:daml-types",
|
||||
"@daml/ledger": "file:daml-ledger"
|
||||
"@daml/types": "file:daml-types"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user