Skip to content

Commit 34f0196

Browse files
committed
Add local template option
1 parent d12e638 commit 34f0196

File tree

17 files changed

+390
-307
lines changed

17 files changed

+390
-307
lines changed

waspc/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ Do the non-bold steps when necessary (decide for each step depending on the chan
432432
- Update the starter templates if necessary (i.e., if there are breaking changes or new features they should make use of):
433433
- Context: they are used by used by `wasp new`, you can find reference to them in `Wasp.Cli. ... .StarterTemplates`.
434434
- Check and merge all PRs with the label `merge-before-release`.
435-
- In `StarterTemplates.hs` file, update git tag to new version of Wasp we are about to release (e.g. `wasp-v0.13.1-template`).
435+
- In `AvailableTemplates.hs` file, update git tag to new version of Wasp we are about to release (e.g. `wasp-v0.13.1-template`).
436436
- Ensure that all starter templates are working with this new version of Wasp.
437-
Update Wasp version in their main.wasp files, and update their code as neccessary. Finally, in their repos (for those templates that are on Github), create new git tag that is the same as the new one in `StarterTemplates.hs` (e.g. `wasp-v0.13.1-template`), and confirm that the GitHub action correctly ran and uploaded a `template.tar.gz` file. Now, once new wasp release is out, it will immediately be able to pull the correct and working version of the starter templates, which is why all this needs to happen before we release new wasp version.
437+
Update Wasp version in their main.wasp files, and update their code as neccessary. Finally, in their repos (for those templates that are on Github), create new git tag that is the same as the new one in `AvailableTemplates.hs` (e.g. `wasp-v0.13.1-template`), and confirm that the GitHub action correctly ran and uploaded a `template.tar.gz` file. Now, once new wasp release is out, it will immediately be able to pull the correct and working version of the starter templates, which is why all this needs to happen before we release new wasp version.
438438
- Open-saas also falls under this!
439439
- Make sure apps in [examples](/examples) are up to date and using a version compatible with the newest version of Wasp.
440440
- Make sure that Wasp AI (which is part of `waspc` and you can run it with e.g. `wasp new:ai`) is correctly producing apps that work with and use this newest version of Wasp.

waspc/cli/exe/Main.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import Wasp.Cli.Command.BuildStart (buildStart)
1717
import qualified Wasp.Cli.Command.Call as Command.Call
1818
import Wasp.Cli.Command.Clean (clean)
1919
import Wasp.Cli.Command.Compile (compile)
20-
import Wasp.Cli.Command.CreateNewProject (createNewProject)
20+
import Wasp.Cli.Command.CreateNewProject (createNewCustomProject, createNewProject)
2121
import qualified Wasp.Cli.Command.CreateNewProject.AI as Command.CreateNewProject.AI
22-
import Wasp.Cli.Command.CreateNewProject.StarterTemplates (availableStarterTemplates)
22+
import Wasp.Cli.Command.CreateNewProject.AvailableTemplates (availableStarterTemplates)
2323
import Wasp.Cli.Command.Db (runCommandThatRequiresDbRunning)
2424
import qualified Wasp.Cli.Command.Db.Migrate as Command.Db.Migrate
2525
import qualified Wasp.Cli.Command.Db.Reset as Command.Db.Reset
@@ -51,6 +51,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
5151
let commandCall = case args of
5252
("new" : newArgs) -> Command.Call.New newArgs
5353
("new:ai" : newAiArgs) -> Command.Call.NewAi newAiArgs
54+
("new:custom" : newCustomArgs) -> Command.Call.NewCustom newCustomArgs
5455
["start"] -> Command.Call.Start
5556
("start" : "db" : startDbArgs) -> Command.Call.StartDb startDbArgs
5657
["clean"] -> Command.Call.Clean
@@ -89,6 +90,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
8990

9091
case commandCall of
9192
Command.Call.New newArgs -> runCommand $ createNewProject newArgs
93+
Command.Call.NewCustom newCustomArgs -> runCommand $ createNewCustomProject newCustomArgs
9294
Command.Call.NewAi newAiArgs -> case newAiArgs of
9395
["--stdout", projectName, appDescription, projectConfigJson] ->
9496
runCommand $

waspc/cli/src/Wasp/Cli/Command/BuildStart/ArgumentsParser.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ module Wasp.Cli.Command.BuildStart.ArgumentsParser
55
where
66

77
import qualified Options.Applicative as Opt
8-
import Wasp.Cli.Util.EnvVarArgument (EnvVarFileArgument, envVarFileReader, envVarReader)
8+
import Wasp.Cli.Util.EnvVarArgument (envVarReader)
9+
import Wasp.Cli.Util.PathArgument (FilePathArgument, filePathReader)
910
import Wasp.Env (EnvVar)
1011

1112
data BuildStartArgs = BuildStartArgs
1213
{ clientEnvironmentVariables :: [EnvVar],
13-
clientEnvironmentFiles :: [EnvVarFileArgument],
14+
clientEnvironmentFiles :: [FilePathArgument],
1415
serverEnvironmentVariables :: [EnvVar],
15-
serverEnvironmentFiles :: [EnvVarFileArgument]
16+
serverEnvironmentFiles :: [FilePathArgument]
1617
}
1718

1819
buildStartArgsParser :: Opt.Parser BuildStartArgs
@@ -41,9 +42,9 @@ buildStartArgsParser =
4142
<> Opt.metavar "NAME=VALUE"
4243
<> Opt.help ("Set an environment variable for the " <> targetName <> " (can be used multiple times)")
4344

44-
makeEnvironmentFileParser :: String -> String -> Opt.Parser EnvVarFileArgument
45+
makeEnvironmentFileParser :: String -> String -> Opt.Parser FilePathArgument
4546
makeEnvironmentFileParser targetName longOptionName =
46-
Opt.option envVarFileReader $
47+
Opt.option filePathReader $
4748
Opt.long longOptionName
4849
<> Opt.metavar "FILE_PATH"
4950
<> Opt.help ("Load environment variables for the " <> targetName <> " from a file (can be used multiple times)")

waspc/cli/src/Wasp/Cli/Command/BuildStart/Config.hs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import qualified Wasp.AppSpec.Valid as ASV
2323
import Wasp.Cli.Command (Command, CommandError (CommandError))
2424
import Wasp.Cli.Command.BuildStart.ArgumentsParser (BuildStartArgs)
2525
import qualified Wasp.Cli.Command.BuildStart.ArgumentsParser as Args
26-
import Wasp.Cli.Util.EnvVarArgument (EnvVarFileArgument, readEnvVarFile)
27-
import Wasp.Env (EnvVar, nubEnvVars, overrideEnvVars)
26+
import Wasp.Cli.Util.PathArgument (FilePathArgument)
27+
import qualified Wasp.Cli.Util.PathArgument as PathArgument
28+
import Wasp.Env (EnvVar, nubEnvVars, overrideEnvVars, parseDotEnvFile)
2829
import Wasp.Generator.Common (ProjectRootDir)
2930
import Wasp.Generator.ServerGenerator.Common (defaultDevServerUrl)
3031
import qualified Wasp.Generator.ServerGenerator.Common as Server
@@ -108,8 +109,11 @@ overrideEnvVarsCommand forced existing =
108109
intercalate ", " duplicateNames
109110
Right combined -> return combined
110111

111-
combineEnvVarsWithEnvFiles :: [EnvVar] -> [EnvVarFileArgument] -> IO [EnvVar]
112+
combineEnvVarsWithEnvFiles :: [EnvVar] -> [FilePathArgument] -> IO [EnvVar]
112113
combineEnvVarsWithEnvFiles pairs files = do
113-
pairsFromFiles <- mapM readEnvVarFile files
114+
pairsFromFiles <- mapM readEnvVarsFromFile files
114115
let allEnvVars = pairs <> concat pairsFromFiles
115116
return $ nubEnvVars allEnvVars
117+
118+
readEnvVarsFromFile :: FilePathArgument -> IO [EnvVar]
119+
readEnvVarsFromFile pathArg = PathArgument.getFilePath pathArg >>= parseDotEnvFile

waspc/cli/src/Wasp/Cli/Command/Call.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Wasp.Cli.Command.Call where
33
data Call
44
= New Arguments
55
| NewAi Arguments
6+
| NewCustom Arguments
67
| Start
78
| StartDb Arguments
89
| Clean

waspc/cli/src/Wasp/Cli/Command/CreateNewProject.hs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Wasp.Cli.Command.CreateNewProject
22
( createNewProject,
3+
createNewCustomProject,
34
)
45
where
56

@@ -9,20 +10,20 @@ import qualified StrongPath as SP
910
import Wasp.Cli.Command (Command)
1011
import Wasp.Cli.Command.Call (Arguments)
1112
import qualified Wasp.Cli.Command.CreateNewProject.AI as AI
12-
import Wasp.Cli.Command.CreateNewProject.ArgumentsParser (newProjectArgsParser)
13+
import Wasp.Cli.Command.CreateNewProject.ArgumentsParser (newCustomProjectArgsParser, newProjectArgsParser)
14+
import Wasp.Cli.Command.CreateNewProject.AvailableTemplates (availableStarterTemplates)
1315
import qualified Wasp.Cli.Command.CreateNewProject.Common as Common
1416
import Wasp.Cli.Command.CreateNewProject.ProjectDescription
1517
( NewProjectDescription (..),
18+
obtainNewCustomProjectDescription,
1619
obtainNewProjectDescription,
1720
)
1821
import Wasp.Cli.Command.CreateNewProject.StarterTemplates
19-
( DirBasedTemplateMetadata (_path),
20-
StarterTemplate (..),
21-
availableStarterTemplates,
22+
( StarterTemplate (..),
2223
getTemplateStartingInstructions,
2324
)
25+
import Wasp.Cli.Command.CreateNewProject.StarterTemplates.Bundled (createProjectOnDiskFromBundledTemplate)
2426
import Wasp.Cli.Command.CreateNewProject.StarterTemplates.GhReleaseArchive (createProjectOnDiskFromGhReleaseArchiveTemplate)
25-
import Wasp.Cli.Command.CreateNewProject.StarterTemplates.GhRepo (createProjectOnDiskFromGhRepoTemplate)
2627
import Wasp.Cli.Command.CreateNewProject.StarterTemplates.Local (createProjectOnDiskFromLocalTemplate)
2728
import Wasp.Cli.Command.Message (cliSendMessageC)
2829
import Wasp.Cli.Util.Parser (parseArguments)
@@ -41,6 +42,19 @@ createNewProject args = do
4142
createProjectOnDisk newProjectDescription
4243
liftIO $ printGettingStartedInstructionsForProject newProjectDescription
4344

45+
-- | It receives all of the arguments that were passed to the `wasp new:custom` command.
46+
createNewCustomProject :: Arguments -> Command ()
47+
createNewCustomProject args = do
48+
newCustomProjectArgs <-
49+
parseArguments "wasp new:custom" newCustomProjectArgsParser args
50+
& either Common.throwProjectCreationError return
51+
52+
newCustomProjectDescription <-
53+
obtainNewCustomProjectDescription newCustomProjectArgs
54+
55+
createProjectOnDisk newCustomProjectDescription
56+
liftIO $ printGettingStartedInstructionsForProject newCustomProjectDescription
57+
4458
createProjectOnDisk :: NewProjectDescription -> Command ()
4559
createProjectOnDisk
4660
NewProjectDescription
@@ -51,12 +65,12 @@ createProjectOnDisk
5165
} = do
5266
cliSendMessageC $ Msg.Start $ "Creating your project from the \"" ++ show template ++ "\" template..."
5367
case template of
54-
GhRepoStarterTemplate ghRepoRef metadata ->
55-
createProjectOnDiskFromGhRepoTemplate absWaspProjectDir projectName appName ghRepoRef $ _path metadata
56-
GhRepoReleaseArchiveTemplate ghRepoRef assetName metadata ->
57-
createProjectOnDiskFromGhReleaseArchiveTemplate absWaspProjectDir projectName appName ghRepoRef assetName $ _path metadata
58-
LocalStarterTemplate metadata ->
59-
liftIO $ createProjectOnDiskFromLocalTemplate absWaspProjectDir projectName appName $ _path metadata
68+
GhRepoReleaseArchiveTemplate {repo = ghRepoRef, archiveName = archiveName', archivePath = archivePath'} ->
69+
createProjectOnDiskFromGhReleaseArchiveTemplate absWaspProjectDir projectName appName ghRepoRef archiveName' archivePath'
70+
BundledStarterTemplate {bundledPath = bundledPath'} ->
71+
liftIO $ createProjectOnDiskFromBundledTemplate absWaspProjectDir projectName appName bundledPath'
72+
LocalStarterTemplate {localPath = localPath'} ->
73+
liftIO $ createProjectOnDiskFromLocalTemplate absWaspProjectDir projectName appName localPath'
6074
AiGeneratedStarterTemplate ->
6175
AI.createNewProjectInteractiveOnDisk absWaspProjectDir appName
6276

waspc/cli/src/Wasp/Cli/Command/CreateNewProject/ArgumentsParser.hs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
module Wasp.Cli.Command.CreateNewProject.ArgumentsParser
22
( NewProjectArgs (..),
33
newProjectArgsParser,
4+
NewCustomProjectArgs (..),
5+
newCustomProjectArgsParser,
46
)
57
where
68

79
import qualified Options.Applicative as Opt
10+
import Wasp.Cli.Util.PathArgument (DirPathArgument, dirPathReader)
811

912
data NewProjectArgs = NewProjectArgs
1013
{ _projectName :: Maybe String,
@@ -27,3 +30,25 @@ newProjectArgsParser =
2730
<> Opt.short 't'
2831
<> Opt.metavar "TEMPLATE_NAME"
2932
<> Opt.help "Template to use for the new project"
33+
34+
data NewCustomProjectArgs = NewCustomProjectArgs
35+
{ _customProjectName :: Maybe String,
36+
_customTemplatePath :: DirPathArgument
37+
}
38+
39+
newCustomProjectArgsParser :: Opt.Parser NewCustomProjectArgs
40+
newCustomProjectArgsParser =
41+
NewCustomProjectArgs
42+
<$> Opt.optional projectNameParser
43+
<*> templateNameParser
44+
where
45+
projectNameParser :: Opt.Parser String
46+
projectNameParser = Opt.strArgument $ Opt.metavar "PROJECT_NAME"
47+
48+
templateNameParser :: Opt.Parser DirPathArgument
49+
templateNameParser =
50+
Opt.option dirPathReader $
51+
Opt.long "path"
52+
<> Opt.short 'p'
53+
<> Opt.metavar "TEMPLATE_PATH"
54+
<> Opt.help "Path to the local directory to use as a starter template"
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{-# LANGUAGE TupleSections #-}
2+
3+
module Wasp.Cli.Command.CreateNewProject.AvailableTemplates
4+
( availableStarterTemplates,
5+
defaultStarterTemplate,
6+
)
7+
where
8+
9+
import StrongPath (reldir)
10+
import qualified System.FilePath as FP
11+
import Wasp.Cli.Command.CreateNewProject.StarterTemplates (StarterTemplate (..), TemplateMetadata (..))
12+
import Wasp.Cli.GithubRepo (GithubRepoRef (GithubRepoRef))
13+
import qualified Wasp.Cli.GithubRepo as GhRepo
14+
import Wasp.Util.Terminal (styleCode, styleText)
15+
16+
availableStarterTemplates :: [StarterTemplate]
17+
availableStarterTemplates =
18+
[ basicStarterTemplate,
19+
minimalStarterTemplate,
20+
openSaasStarterTemplate,
21+
AiGeneratedStarterTemplate
22+
]
23+
24+
defaultStarterTemplate :: StarterTemplate
25+
defaultStarterTemplate = basicStarterTemplate
26+
27+
{- HLINT ignore minimalStarterTemplate "Redundant $" -}
28+
29+
minimalStarterTemplate :: StarterTemplate
30+
minimalStarterTemplate =
31+
BundledStarterTemplate
32+
{ bundledPath = [reldir|minimal|],
33+
metadata =
34+
TemplateMetadata
35+
{ _name = "minimal",
36+
_description = "A minimal starter template that features just a single page.",
37+
_buildStartingInstructions = \projectDirName ->
38+
unlines
39+
[ styleText $ "To run your new app, do:",
40+
styleCode $ " cd " <> projectDirName,
41+
styleCode $ " wasp start"
42+
]
43+
}
44+
}
45+
46+
{- HLINT ignore basicStarterTemplate "Redundant $" -}
47+
48+
basicStarterTemplate :: StarterTemplate
49+
basicStarterTemplate =
50+
BundledStarterTemplate
51+
{ bundledPath = [reldir|basic|],
52+
metadata =
53+
TemplateMetadata
54+
{ _name = "basic",
55+
_description = "A basic starter template designed to help you get up and running quickly. It features examples covering the most common use cases.",
56+
_buildStartingInstructions = \projectDirName ->
57+
unlines
58+
[ styleText $ "To run your new app, do:",
59+
styleCode $ " cd " <> projectDirName,
60+
styleCode $ " wasp db migrate-dev",
61+
styleCode $ " wasp start",
62+
styleText $ "",
63+
styleText $ "Check the " <> styleCode "README.md" <> " for additional guidance!"
64+
]
65+
}
66+
}
67+
68+
{- HLINT ignore openSaasStarterTemplate "Redundant $" -}
69+
70+
openSaasStarterTemplate :: StarterTemplate
71+
openSaasStarterTemplate =
72+
GhRepoReleaseArchiveTemplate
73+
{ repo =
74+
GithubRepoRef
75+
{ _repoOwner = "wasp-lang",
76+
_repoName = "open-saas",
77+
_repoReferenceName = waspVersionTemplateGitTag
78+
},
79+
archiveName = "template.tar.gz",
80+
archivePath = [reldir|.|],
81+
metadata =
82+
TemplateMetadata
83+
{ _name = "saas",
84+
_description =
85+
"Everything a SaaS needs! Comes with Auth, ChatGPT API, Tailwind, Stripe payments and more."
86+
<> " Check out https://opensaas.sh/ for more details.",
87+
_buildStartingInstructions = \projectDirName ->
88+
unlines
89+
[ styleText $ "To run your new app, follow the instructions below:",
90+
styleText $ "",
91+
styleText $ " 1. Position into app's root directory:",
92+
styleCode $ " cd " <> projectDirName FP.</> "app",
93+
styleText $ "",
94+
styleText $ " 2. Run the development database (and leave it running):",
95+
styleCode $ " wasp db start",
96+
styleText $ "",
97+
styleText $ " 3. Open new terminal window (or tab) in that same dir and continue in it.",
98+
styleText $ "",
99+
styleText $ " 4. Apply initial database migrations:",
100+
styleCode $ " wasp db migrate-dev",
101+
styleText $ "",
102+
styleText $ " 5. Create initial dot env file from the template:",
103+
styleCode $ " cp .env.server.example .env.server",
104+
styleText $ "",
105+
styleText $ " 6. Last step: run the app!",
106+
styleCode $ " wasp start",
107+
styleText $ "",
108+
styleText $ "Check the README for additional guidance and the link to docs!"
109+
]
110+
}
111+
}
112+
113+
-- NOTE: As version of Wasp CLI changes, so we should update this tag name here,
114+
-- and also create it on gh repos of templates.
115+
-- By tagging templates for each version of Wasp CLI, we ensure that each release of
116+
-- Wasp CLI uses correct version of templates, that work with it.
117+
waspVersionTemplateGitTag :: String
118+
waspVersionTemplateGitTag = "wasp-v0.18-template"

0 commit comments

Comments
 (0)