Something went wrong. Try again.
A collection of reusable WebAssembly modules for building composable CI/CD pipelines with FluentCI
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122module CI.Setup.PureScript (Config, Toolchain, defaultConfig, decodeConfig, setupWith, setup) where
import Preludeimport CI.Setup as Setupimport CI.Setup.BSD as BSDimport CI.Setup.Host as Himport CI.Setup.Types as Typesimport Data.Argonaut.Core (Json, isNull, stringify)import Data.Argonaut.Decode (class DecodeJson, decodeJson, getFieldOptional)import Data.Argonaut.Encode (encodeJson)import Data.Argonaut.Parser (jsonParser)import Data.Array as Arrayimport Data.Either (Either(..), either)import Data.Foldable (traverse_)import Data.Maybe (Maybe(..), fromMaybe)import Data.String as Stringimport Data.String.CodeUnits as CUimport Data.String.Common (trim)import Data.String.Pattern (Pattern(..))import Effect (Effect)import Effect.Exception (throw)import FluentCI.Plugin as Pimport Foreign.Object as Object
type Config = { version :: String, nodeVersion :: String, bunVersion :: String , spagoVersion :: String, npmVersion :: String, installDir :: String , sudo :: Boolean, packageName :: String, nodePackageName :: String, bunPackageName :: String }
type Toolchain = { tool :: String, version :: String, binDir :: String, environment :: Object.Object String , nodeVersion :: String, bunVersion :: String, spagoVersion :: String, npmVersion :: String }
defaultConfig :: ConfigdefaultConfig = { version: "latest", nodeVersion: "lts", bunVersion: "latest", spagoVersion: "latest" , npmVersion: "10.9.2", installDir: "", sudo: false, packageName: "", nodePackageName: "", bunPackageName: "" }
optional :: forall a. DecodeJson a => Object.Object Json -> String -> a -> Either String aoptional object key fallback = either (Left <<< show) (Right <<< fromMaybe fallback) (getFieldOptional object key)
decodeConfig :: Json -> Either String ConfigdecodeConfig json = do object <- either (Left <<< show) pure (decodeJson json) let allowed = [ "version", "nodeVersion", "bunVersion", "spagoVersion", "npmVersion", "installDir", "sudo", "packageName", "nodePackageName", "bunPackageName" ] when (Array.any isNull (Object.values object)) $ Left "Toolchain arguments cannot be null" case Array.find (\key -> not (Array.elem key allowed)) (Object.keys object) of Just key -> Left ("Unknown PureScript setup argument: " <> key) Nothing -> pure unit version <- optional object "version" defaultConfig.version nodeVersion <- optional object "nodeVersion" defaultConfig.nodeVersion bunVersion <- optional object "bunVersion" defaultConfig.bunVersion spagoVersion <- optional object "spagoVersion" defaultConfig.spagoVersion npmVersion <- optional object "npmVersion" defaultConfig.npmVersion installDir <- optional object "installDir" defaultConfig.installDir sudo <- optional object "sudo" defaultConfig.sudo packageName <- optional object "packageName" defaultConfig.packageName nodePackageName <- optional object "nodePackageName" defaultConfig.nodePackageName bunPackageName <- optional object "bunPackageName" defaultConfig.bunPackageName pure { version, nodeVersion, bunVersion, spagoVersion, npmVersion, installDir, sudo, packageName, nodePackageName, bunPackageName }
setupWith :: Config -> Effect ToolchainsetupWith config = do traverse_ (\version -> unless (Types.versionToken version) (throw "Invalid toolchain version token")) [ config.version, config.nodeVersion, config.bunVersion, config.spagoVersion, config.npmVersion ] let npmParts = String.split (Pattern ".") config.npmVersion unless (Array.length npmParts == 3 && Array.all (\part -> CU.length part > 0 && Array.all (\c -> c >= '0' && c <= '9') (CU.toCharArray part)) npmParts) $ throw "npmVersion must be an exact numeric release" traverse_ (\packageName -> either throw pure (Types.validateConfig "purescript" ((Types.defaults "node") { version = config.version, installDir = config.installDir, packageName = packageName }))) [ config.packageName, config.nodePackageName, config.bunPackageName ] host <- H.host either throw pure (Types.hostSupported "node" host) let bsd = Types.isBSD host.os unless (bsd || (not config.sudo && Array.all (_ == "") [ config.packageName, config.nodePackageName, config.bunPackageName ])) $ throw "sudo and package selectors apply only to native BSD packages" H.requireTools [ "curl", "tar", "mktemp", "mkdir", "rm" ] node <- Setup.install "node" ((Types.defaults "node") { version = config.nodeVersion, sudo = config.sudo, packageName = config.nodePackageName }) bun <- Setup.install "bun" ((Types.defaults "bun") { version = config.bunVersion, sudo = config.sudo, packageName = config.bunPackageName }) home <- if config.installDir == "" then H.userHome else pure "" let prefix = if config.installDir == "" then home <> "/.local/share/fluentci/purescript/" <> config.version else Types.cleanDirectory config.installDir binDir = prefix <> "/node_modules/.bin" native <- if bsd then do compiler <- BSD.install "purescript" host ((Types.defaults "purescript") { version = config.version, sudo = config.sudo, packageName = config.packageName }) H.activate compiler pure (Just compiler) else pure Nothing H.run [ "mkdir", "-p", prefix ] -- Bootstrap npm as portable JavaScript, including on BSD where Node packages -- may not include npm. Keep npm installed alongside purs and Spago afterwards. H.withTemp \temp -> do H.download ("https://registry.npmjs.org/npm/-/npm-" <> config.npmVersion <> ".tgz") (temp <> "/npm.tgz") H.run [ "tar", "-xzf", temp <> "/npm.tgz", "-C", temp ] H.run ([ node.binDir <> "/node", temp <> "/package/bin/npm-cli.js", "install", "--prefix", prefix , "--no-audit", "--no-fund", "--save-exact", "npm@" <> config.npmVersion, "spago@" <> config.spagoVersion ] <> if bsd then [] else [ "purescript@" <> config.version ]) version <- case native of Just compiler -> pure compiler.version Nothing -> H.verify "purescript" config.version (binDir <> "/purs") spagoVersion <- H.verify "spago" config.spagoVersion (binDir <> "/spago") npmVersion <- H.verify "npm" config.npmVersion (binDir <> "/npm") result <- H.result "purescript" version binDir Object.empty H.activate result pure { tool: result.tool, version, binDir, environment: result.environment , nodeVersion: node.version, bunVersion: bun.version, spagoVersion, npmVersion }
setup :: Effect Unitsetup = do raw <- trim <$> (P.input >>= H.unwrap) config <- if raw == "" then pure defaultConfig else if String.startsWith (Pattern "{") raw then either throw pure (jsonParser raw >>= decodeConfig) else pure (defaultConfig { version = raw }) result <- setupWith config P.output (stringify (encodeJson result)) >>= H.unwrap