diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ff04ca1b..1cf620a6 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,10 +16,10 @@ jobs: uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }} diff --git a/.github/workflows/generate-linter-advanced.yml b/.github/workflows/generate-linter-advanced.yml index cc673d52..de92801b 100644 --- a/.github/workflows/generate-linter-advanced.yml +++ b/.github/workflows/generate-linter-advanced.yml @@ -8,9 +8,11 @@ jobs: framework_matrix: strategy: matrix: - framework: [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] + framework: + [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] driver: [postgres] git: [commit] + builder: [just, make] advanced: [htmx, githubaction, websocket, tailwind, docker, react] runs-on: ubuntu-latest @@ -20,7 +22,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.23.x' + go-version: "1.23.x" - name: Install golangci-lint run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4 @@ -35,16 +37,16 @@ jobs: run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV - name: build templates - run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} --advanced --feature ${{ matrix.advanced }}" + run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} -br ${{ matrix.builder}} --advanced --feature ${{ matrix.advanced }}" - if: ${{ matrix.advanced == 'htmx' || matrix.advanced == 'tailwind' }} name: Install Templ & gen templates - run: | + run: | go install github.com/a-h/templ/cmd/templ@latest /home/runner/go/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }} - name: golangci-lint - run: | + run: | cd ${{ env.PROJECT_DIRECTORY }} golangci-lint run diff --git a/.github/workflows/generate-linter-core.yml b/.github/workflows/generate-linter-core.yml index cf1e6045..e68da88c 100644 --- a/.github/workflows/generate-linter-core.yml +++ b/.github/workflows/generate-linter-core.yml @@ -8,9 +8,11 @@ jobs: framework_matrix: strategy: matrix: - framework: [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] + framework: + [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] driver: [mysql, postgres, sqlite, mongo, redis, scylla, none] git: [commit, stage, skip] + builder: [just] runs-on: ubuntu-latest steps: @@ -19,7 +21,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.23.x' + go-version: "1.23.x" - name: Install golangci-lint run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4 @@ -34,10 +36,10 @@ jobs: run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV - name: build templates - run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}}" + run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} -br ${{ matrix.builder}}" - name: golangci-lint - run: | + run: | cd ${{ env.PROJECT_DIRECTORY }} golangci-lint run diff --git a/.github/workflows/testcontainers.yml b/.github/workflows/testcontainers.yml index ec2109e7..5888bcfd 100644 --- a/.github/workflows/testcontainers.yml +++ b/.github/workflows/testcontainers.yml @@ -8,15 +8,14 @@ jobs: itests_matrix: strategy: matrix: - driver: - [mysql, postgres, mongo, redis, scylla] + driver: [mysql, postgres, mongo, redis, scylla] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.23.x' + go-version: "1.23.x" - name: Commit report run: | @@ -24,7 +23,7 @@ jobs: git config --global user.email 'testemail@users.noreply.github.com' - name: build ${{ matrix.driver }} template - run: script -q /dev/null -c "go run main.go create -n ${{ matrix.driver }} -g commit -f fiber -d ${{matrix.driver}}" + run: script -q /dev/null -c "go run main.go create -n ${{ matrix.driver }} -g commit -b just -f fiber -d ${{matrix.driver}}" - name: run ${{ matrix.driver }} integration tests working-directory: ${{ matrix.driver }} diff --git a/README.md b/README.md index f2ec319b..1080cb0f 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,18 @@ See `go-blueprint create -h` for all the options and shorthands. - [Gorilla/mux](https://github.com/gorilla/mux) - [Echo](https://github.com/labstack/echo) + + +
+ @@ -206,7 +218,7 @@ go-blueprint create --advanced --feature react Or all features at once: ```bash -go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --git commit --feature react +go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --git commit --builder just --feature react ```
diff --git a/cmd/create.go b/cmd/create.go index 8a46bc09..ebb98176 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -44,6 +44,7 @@ func init() { var flagDBDriver flags.Database var advancedFeatures flags.AdvancedFeatures var flagGit flags.Git + var flagBuilder flags.Builder rootCmd.AddCommand(createCmd) createCmd.Flags().StringP("name", "n", "", "Name of project to create") @@ -52,6 +53,13 @@ func init() { createCmd.Flags().BoolP("advanced", "a", false, "Get prompts for advanced features") createCmd.Flags().Var(&advancedFeatures, "feature", fmt.Sprintf("Advanced feature to use. Allowed values: %s", strings.Join(flags.AllowedAdvancedFeatures, ", "))) createCmd.Flags().VarP(&flagGit, "git", "g", fmt.Sprintf("Git to use. Allowed values: %s", strings.Join(flags.AllowedGitsOptions, ", "))) + createCmd.Flags().VarP(&flagBuilder, "builder", "br", fmt.Sprintf("Builder to use. Allowed values: %s", strings.Join(flags.AllowedBuilders, ", "))) + + utils.RegisterStaticCompletions(createCmd, "framework", flags.AllowedProjectTypes) + utils.RegisterStaticCompletions(createCmd, "driver", flags.AllowedDBDrivers) + utils.RegisterStaticCompletions(createCmd, "feature", flags.AllowedAdvancedFeatures) + utils.RegisterStaticCompletions(createCmd, "git", flags.AllowedGitsOptions) + utils.RegisterStaticCompletions(createCmd, "builder", flags.AllowedBuilders) } type Options struct { @@ -61,6 +69,7 @@ type Options struct { Advanced *multiSelect.Selection Workflow *multiInput.Selection Git *multiInput.Selection + Builder *multiInput.Selection } // createCmd defines the "create" command for the CLI @@ -92,6 +101,7 @@ var createCmd = &cobra.Command{ flagFramework := flags.Framework(cmd.Flag("framework").Value.String()) flagDBDriver := flags.Database(cmd.Flag("driver").Value.String()) flagGit := flags.Git(cmd.Flag("git").Value.String()) + flagBuilder := flags.Builder(cmd.Flag("builder").Value.String()) options := Options{ ProjectName: &textinput.Output{}, @@ -101,6 +111,7 @@ var createCmd = &cobra.Command{ Choices: make(map[string]bool), }, Git: &multiInput.Selection{}, + Builder: &multiInput.Selection{}, } project := &program.Project{ @@ -109,8 +120,10 @@ var createCmd = &cobra.Command{ DBDriver: flagDBDriver, FrameworkMap: make(map[flags.Framework]program.Framework), DBDriverMap: make(map[flags.Database]program.Driver), + BuilderMap: make(map[flags.Builder]program.Builder), AdvancedOptions: make(map[string]bool), GitOptions: flagGit, + Builder: flagBuilder, } steps := steps.InitSteps(flagFramework, flagDBDriver) @@ -238,6 +251,21 @@ var createCmd = &cobra.Command{ } } + if project.Builder == "" { + isInteractive = true + step := steps.Steps["builder"] + tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.Builder, step.Headers, project)) + if _, err := tprogram.Run(); err != nil { + cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) + } + project.ExitCLI(tprogram) + + project.Builder = flags.Builder(strings.ToLower(options.Builder.Choice)) + err := cmd.Flag("builder").Value.Set(project.Builder.String()) + if err != nil { + log.Fatal("failed to set the builder flag value: ", err) + } + } currentWorkingDir, err := os.Getwd() if err != nil { log.Printf("could not get current working directory: %v", err) @@ -273,7 +301,7 @@ var createCmd = &cobra.Command{ if releaseErr := spinner.ReleaseTerminal(); releaseErr != nil { log.Printf("Problem releasing terminal: %v", releaseErr) } - log.Printf("Problem creating files for project. %v", err) + log.Printf("Problem creating files for project.") cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) } diff --git a/cmd/flags/builder.go b/cmd/flags/builder.go new file mode 100644 index 00000000..6e336057 --- /dev/null +++ b/cmd/flags/builder.go @@ -0,0 +1,37 @@ + +package flags + +import ( + "fmt" + "strings" +) + +type Builder string + +const ( + Make Builder = "make" + Just Builder = "just" +) + +var AllowedBuilders = []string{string(Make), string(Just)} + +func (f Builder) String() string { + return string(f) +} + +func (f *Builder) Type() string { + return "Database" +} + +func (f *Builder) Set(value string) error { + // Contains isn't available in 1.20 yet + // if AllowedDBDrivers.Contains(value) { + for _, builder := range AllowedBuilders { + if builder == value { + *f = Builder(value) + return nil + } + } + + return fmt.Errorf("Builder to use. Allowed values: %s", strings.Join(AllowedBuilders, ", ")) +} diff --git a/cmd/program/program.go b/cmd/program/program.go index b5a8465b..dc972907 100644 --- a/cmd/program/program.go +++ b/cmd/program/program.go @@ -17,6 +17,7 @@ import ( "github.com/melkeydev/go-blueprint/cmd/flags" tpl "github.com/melkeydev/go-blueprint/cmd/template" "github.com/melkeydev/go-blueprint/cmd/template/advanced" + "github.com/melkeydev/go-blueprint/cmd/template/builder" "github.com/melkeydev/go-blueprint/cmd/template/dbdriver" "github.com/melkeydev/go-blueprint/cmd/template/docker" "github.com/melkeydev/go-blueprint/cmd/template/framework" @@ -34,10 +35,12 @@ type Project struct { Docker flags.Database FrameworkMap map[flags.Framework]Framework DBDriverMap map[flags.Database]Driver + BuilderMap map[flags.Builder]Builder DockerMap map[flags.Database]Docker AdvancedOptions map[string]bool AdvancedTemplates AdvancedTemplates GitOptions flags.Git + Builder flags.Builder OSCheck map[string]bool } @@ -63,6 +66,12 @@ type Docker struct { templater DockerTemplater } +type Builder struct { + filename string + commandName string + templater func() []byte +} + // A Templater has the methods that help build the files // in the Project folder, and is specific to a Framework type Templater interface { @@ -90,7 +99,6 @@ type WorkflowTemplater interface { Test() []byte ReleaserConfig() []byte } - var ( chiPackage = []string{"github.com/go-chi/chi/v5"} gorillaPackage = []string{"github.com/gorilla/mux"} @@ -100,7 +108,7 @@ var ( echoPackage = []string{"github.com/labstack/echo/v4", "github.com/labstack/echo/v4/middleware"} mysqlDriver = []string{"github.com/go-sql-driver/mysql"} - postgresDriver = []string{"github.com/lib/pq"} + postgresDriver = []string{"github.com/jackc/pgx/v5/stdlib"} sqliteDriver = []string{"github.com/mattn/go-sqlite3"} redisDriver = []string{"github.com/redis/go-redis/v9"} mongoDriver = []string{"go.mongodb.org/mongo-driver"} @@ -120,7 +128,7 @@ const ( gitHubActionPath = ".github/workflows" ) -// CheckOs checks Operation system and generates MakeFile and `go build` command +// CheckOs checks Operation system and generates MakeFile/justfile and `go build` command // Based on Project.Unixbase func (p *Project) CheckOS() { p.OSCheck = make(map[string]bool) @@ -215,6 +223,11 @@ func (p *Project) createDBDriverMap() { } } +func (p *Project) createBuilderMap() { + p.BuilderMap[flags.Make] = Builder{"Makefile", "make", builder.MakeTemplate} + p.BuilderMap[flags.Just] = Builder{"justfile", "just", builder.JustTemplate} +} + func (p *Project) createDockerMap() { p.DockerMap = make(map[flags.Database]Docker) @@ -253,15 +266,17 @@ func (p *Project) CreateMainFile() error { } // Check if user.email is set. - emailSet, err := utils.CheckGitConfig("user.email") - if err != nil { - return err - } + if p.GitOptions.String() != flags.Skip { - if !emailSet && p.GitOptions.String() != flags.Skip { - fmt.Println("user.email is not set in git config.") - fmt.Println("Please set up git config before trying again.") - panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n") + emailSet, err := utils.CheckGitConfig("user.email") + if err != nil { + return err + } + if !emailSet { + fmt.Println("user.email is not set in git config.") + fmt.Println("Please set up git config before trying again.") + panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n") + } } p.ProjectName = strings.TrimSpace(p.ProjectName) @@ -283,7 +298,7 @@ func (p *Project) CreateMainFile() error { p.createFrameworkMap() // Create go.mod - err = utils.InitGoMod(p.ProjectName, projectPath) + err := utils.InitGoMod(p.ProjectName, projectPath) if err != nil { log.Printf("Could not initialize go.mod in new project %v\n", err) return err @@ -293,7 +308,7 @@ func (p *Project) CreateMainFile() error { if p.ProjectType != flags.StandardLibrary { err = utils.GoGetPackage(projectPath, p.FrameworkMap[p.ProjectType].packageName) if err != nil { - log.Printf("Could not install go dependency for the chosen framework %v\n", err) + log.Println("Could not install go dependency for the chosen framework") return err } } @@ -303,7 +318,7 @@ func (p *Project) CreateMainFile() error { p.createDBDriverMap() err = utils.GoGetPackage(projectPath, p.DBDriverMap[p.DBDriver].packageName) if err != nil { - log.Printf("Could not install go dependency for chosen driver %v\n", err) + log.Println("Could not install go dependency for chosen driver") return err } @@ -346,9 +361,8 @@ func (p *Project) CreateMainFile() error { // Install the godotenv package err = utils.GoGetPackage(projectPath, godotenvPackage) - if err != nil { - log.Printf("Could not install go dependency %v\n", err) + log.Println("Could not install go dependency") return err } @@ -373,16 +387,18 @@ func (p *Project) CreateMainFile() error { return err } - makeFile, err := os.Create(filepath.Join(projectPath, "Makefile")) + + p.createBuilderMap() + builderFile, err := os.Create(filepath.Join(projectPath, p.BuilderMap[p.Builder].filename)) if err != nil { return err } - defer makeFile.Close() + defer builderFile.Close() - // inject makefile template - makeFileTemplate := template.Must(template.New("makefile").Parse(string(framework.MakeTemplate()))) - err = makeFileTemplate.Execute(makeFile, p) + // inject builderfile template + builderFileTemplate := template.Must(template.New(p.BuilderMap[p.Builder].filename).Parse(string(p.BuilderMap[p.Builder].templater()))) + err = builderFileTemplate.Execute(builderFile, p) if err != nil { return err } @@ -421,18 +437,6 @@ func (p *Project) CreateMainFile() error { // select htmx option automatically since tailwind is selected p.AdvancedOptions[string(flags.Htmx)] = true - tailwindConfigFile, err := os.Create(fmt.Sprintf("%s/tailwind.config.js", projectPath)) - if err != nil { - return err - } - defer tailwindConfigFile.Close() - - tailwindConfigTemplate := advanced.TailwindConfigTemplate() - err = os.WriteFile(fmt.Sprintf("%s/tailwind.config.js", projectPath), tailwindConfigTemplate, 0o644) - if err != nil { - return err - } - err = os.MkdirAll(fmt.Sprintf("%s/%s/assets/css", projectPath, cmdWebPath), 0o755) if err != nil { return err @@ -529,7 +533,7 @@ func (p *Project) CreateMainFile() error { } err = utils.GoGetPackage(projectPath, templPackage) if err != nil { - log.Printf("Could not install go dependency %v\n", err) + log.Println("Could not install go dependency") return err } @@ -547,7 +551,7 @@ func (p *Project) CreateMainFile() error { } err = utils.GoGetPackage(projectPath, []string{"github.com/gofiber/fiber/v2/middleware/adaptor"}) if err != nil { - log.Printf("Could not install go dependency %v\n", err) + log.Println("Could not install go dependency") return err } } else { @@ -691,12 +695,12 @@ func (p *Project) CreateMainFile() error { return err } - nameSet, err := utils.CheckGitConfig("user.name") - if err != nil { - return err - } - if p.GitOptions != flags.Skip { + nameSet, err := utils.CheckGitConfig("user.name") + if err != nil { + return err + } + if !nameSet { fmt.Println("user.name is not set in git config.") fmt.Println("Please set up git config before trying again.") @@ -891,25 +895,16 @@ func (p *Project) CreateViteReactProject(projectPath string) error { cmd := exec.Command("npm", "install", "--prefer-offline", "--no-fund", - "tailwindcss", "postcss", "autoprefixer") + "tailwindcss@^4", "@tailwindcss/vite") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed to install Tailwind: %w", err) } - fmt.Println("Initializing Tailwind...") - cmd = exec.Command("npx", "--prefer-offline", "tailwindcss", "init", "-p") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to initialize Tailwind: %w", err) - } - - // use the tailwind config file - err = os.WriteFile("tailwind.config.js", advanced.ReactTailwindConfigTemplate(), 0644) - if err != nil { - return fmt.Errorf("failed to write tailwind config: %w", err) + // Create the vite + react + Tailwind v4 configuration + if err := os.WriteFile(filepath.Join(frontendPath, "vite.config.ts"), advanced.ViteTailwindConfigFile(), 0644); err != nil { + return fmt.Errorf("failed to write vite.config.ts: %w", err) } srcDir := filepath.Join(frontendPath, "src") @@ -939,6 +934,7 @@ func (p *Project) CreateViteReactProject(projectPath string) error { return nil } + func (p *Project) CreateHtmxTemplates() { routesPlaceHolder := "" importsPlaceHolder := "" diff --git a/cmd/steps/steps.go b/cmd/steps/steps.go index eacb874b..e48b1dab 100644 --- a/cmd/steps/steps.go +++ b/cmd/steps/steps.go @@ -146,6 +146,20 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps }, }, }, + "builder": { + StepName: "Builder", + Headers: "Which builder would you like to select for your project?", + Options: []Item{ + { + Title: "Make", + Desc: "Standard GNU project builder", + }, + { + Title: "Just", + Desc: "Modern, task-focused command runner with simpler syntax", + }, + }, + }, }, } diff --git a/cmd/template/advanced/files/docker/dockerfile.tmpl b/cmd/template/advanced/files/docker/dockerfile.tmpl index c2042ed6..961b5a56 100644 --- a/cmd/template/advanced/files/docker/dockerfile.tmpl +++ b/cmd/template/advanced/files/docker/dockerfile.tmpl @@ -16,7 +16,7 @@ RUN go install github.com/a-h/templ/cmd/templ@latest && \ {{- end}} {{- if .AdvancedOptions.tailwind}} - curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-linux-x64 -o tailwindcss && \ + curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss && \ chmod +x tailwindcss && \ ./tailwindcss -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css {{- end }} diff --git a/cmd/template/advanced/files/react/tailwind/index.css.tmpl b/cmd/template/advanced/files/react/tailwind/index.css.tmpl index b5c61c95..a461c505 100644 --- a/cmd/template/advanced/files/react/tailwind/index.css.tmpl +++ b/cmd/template/advanced/files/react/tailwind/index.css.tmpl @@ -1,3 +1 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; \ No newline at end of file diff --git a/cmd/template/advanced/files/react/tailwind/tailwind.config.js.tmpl b/cmd/template/advanced/files/react/tailwind/tailwind.config.js.tmpl deleted file mode 100644 index 89a305e0..00000000 --- a/cmd/template/advanced/files/react/tailwind/tailwind.config.js.tmpl +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", - ], - theme: { - extend: {}, - }, - plugins: [], -} \ No newline at end of file diff --git a/cmd/template/advanced/files/react/tailwind/vite.config.ts.tmpl b/cmd/template/advanced/files/react/tailwind/vite.config.ts.tmpl new file mode 100644 index 00000000..6370c075 --- /dev/null +++ b/cmd/template/advanced/files/react/tailwind/vite.config.ts.tmpl @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(),tailwindcss()], +}) \ No newline at end of file diff --git a/cmd/template/advanced/files/tailwind/input.css.tmpl b/cmd/template/advanced/files/tailwind/input.css.tmpl index b5c61c95..73a943cd 100644 --- a/cmd/template/advanced/files/tailwind/input.css.tmpl +++ b/cmd/template/advanced/files/tailwind/input.css.tmpl @@ -1,3 +1 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss" diff --git a/cmd/template/advanced/files/tailwind/tailwind.config.js.tmpl b/cmd/template/advanced/files/tailwind/tailwind.config.js.tmpl deleted file mode 100644 index 4ec34519..00000000 --- a/cmd/template/advanced/files/tailwind/tailwind.config.js.tmpl +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: [ - "./cmd/web/**/*.html", "./cmd/web/**/*.templ", - ], - theme: { - extend: {}, - }, - plugins: [], -} - diff --git a/cmd/template/advanced/routes.go b/cmd/template/advanced/routes.go index 3ed424f6..e7860f58 100644 --- a/cmd/template/advanced/routes.go +++ b/cmd/template/advanced/routes.go @@ -10,15 +10,12 @@ var helloTemplTemplate []byte //go:embed files/htmx/base.templ.tmpl var baseTemplTemplate []byte -//go:embed files/tailwind/tailwind.config.js.tmpl -var tailwindConfigTemplate []byte - -//go:embed files/react/tailwind/tailwind.config.js.tmpl -var reactTailwindConfigTemplate []byte - //go:embed files/react/tailwind/index.css.tmpl var inputCssTemplateReact []byte +//go:embed files/react/tailwind/vite.config.ts.tmpl +var viteTailwindConfigFile []byte + //go:embed files/react/tailwind/app.tsx.tmpl var reactTailwindAppFile []byte @@ -119,14 +116,6 @@ func BaseTemplTemplate() []byte { return baseTemplTemplate } -func TailwindConfigTemplate() []byte { - return tailwindConfigTemplate -} - -func ReactTailwindConfigTemplate() []byte { - return reactTailwindConfigTemplate -} - func ReactTailwindAppfile() []byte { return reactTailwindAppFile } @@ -139,6 +128,10 @@ func InputCssTemplateReact() []byte { return inputCssTemplateReact } +func ViteTailwindConfigFile() []byte { + return viteTailwindConfigFile +} + func InputCssTemplate() []byte { return inputCssTemplate } diff --git a/cmd/template/builder/files/justfile.tmpl b/cmd/template/builder/files/justfile.tmpl new file mode 100644 index 00000000..edde0ea9 --- /dev/null +++ b/cmd/template/builder/files/justfile.tmpl @@ -0,0 +1,143 @@ +# Simple justfile for a Go project + +# Build the application +all: build test + +{{- if (not .OSCheck.UnixBased) }} +set shell := ["powershell.exe", "-c"] +{{- end }} + +{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} +{{- if .OSCheck.UnixBased }} +templ-install: + if ! command -v templ > /dev/null; then \ + read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/a-h/templ/cmd/templ@latest; \ + if [ ! -x "$$(command -v templ)" ]; then \ + echo "templ installation failed. Exiting..."; \ + exit 1; \ + fi; \ + else \ + echo "You chose not to install templ. Exiting..."; \ + exit 1; \ + fi; \ + fi +{{- else }} +templ-install: + powershell -ExecutionPolicy Bypass -Command "if (Get-Command templ -ErrorAction SilentlyContinue) { \ + ; \ + } else { \ + Write-Output 'Installing templ...'; \ + go install github.com/a-h/templ/cmd/templ@latest; \ + if (-not (Get-Command templ -ErrorAction SilentlyContinue)) { \ + Write-Output 'templ installation failed. Exiting...'; \ + exit 1; \ + } else { \ + Write-Output 'templ installed successfully.'; \ + } \ + }" +{{- end }} +{{- end }} + +{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} +{{- if .OSCheck.UnixBased}} +tailwind-install: + {{ if .OSCheck.linux }}if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi{{- end }} + {{ if .OSCheck.darwin }}if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-x64 -o tailwindcss; fi{{- end }} + chmod +x tailwindcss +{{- else }} +tailwind-install: + if not exist tailwindcss.exe powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-windows-x64.exe' -OutFile 'tailwindcss.exe'"{{- end }} +{{- end }} + +build:{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} tailwind-install{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }} + echo "Building..." + {{ if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }}templ generate{{- end }} + {{ if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }}{{ if .OSCheck.UnixBased }}./tailwindcss{{ else }}.\tailwindcss.exe{{ end }} -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css{{ end }} + {{ if .OSCheck.UnixBased }}{{- if and (.AdvancedOptions.docker) (eq .DBDriver "sqlite") }}CGO_ENABLED=1 GOOS=linux {{ end }}go build -o main cmd/api/main.go{{- else }}go build -o main.exe cmd/api/main.go{{- end }} + +# Run the application +run: + go run cmd/api/main.go{{- if .AdvancedOptions.react }} & + npm install --prefer-offline --no-fund --prefix ./frontend + npm run dev --prefix ./frontend + {{- end }} + + +{{- if or .AdvancedOptions.docker (and (ne .DBDriver "none") (ne .DBDriver "sqlite")) }} +{{- if .OSCheck.UnixBased }} +# Create DB container +docker-run: + if docker compose up --build 2>/dev/null; then \ + : ; \ + else \ + echo "Falling back to Docker Compose V1"; \ + docker-compose up --build; \ + fi + +# Shutdown DB container +docker-down: + if docker compose down 2>/dev/null; then \ + : ; \ + else \ + echo "Falling back to Docker Compose V1"; \ + docker-compose down; \ + fi +{{- else }} +# Create DB container +docker-run: + docker compose up --build + +# Shutdown DB container +docker-down: + docker compose down +{{- end }} +{{- end }} + +# Test the application +test: + echo "Testing..." + go test ./... -v + +{{- if and (ne .DBDriver "none") (ne .DBDriver "sqlite") }} +# Integrations Tests for the application +itest: + echo "Running integration tests..." + go test ./internal/database -v +{{- end }} + +# Clean the binary +clean: + echo "Cleaning..." + rm -f main + +# Live Reload +{{- if .OSCheck.UnixBased }} +watch: + if command -v air > /dev/null; then \ + air; \ + echo "Watching...";\ + else \ + read -p "Go's 'air' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/air-verse/air@latest; \ + air; \ + echo "Watching...";\ + else \ + echo "You chose not to install air. Exiting..."; \ + exit 1; \ + fi; \ + fi +{{- else }} +watch: + powershell -ExecutionPolicy Bypass -Command "if (Get-Command air -ErrorAction SilentlyContinue) { \ + air; \ + Write-Output 'Watching...'; \ + } else { \ + Write-Output 'Installing air...'; \ + go install github.com/air-verse/air@latest; \ + air; \ + Write-Output 'Watching...'; \ + }" +{{- end }} diff --git a/cmd/template/framework/files/makefile.tmpl b/cmd/template/builder/files/makefile.tmpl similarity index 93% rename from cmd/template/framework/files/makefile.tmpl rename to cmd/template/builder/files/makefile.tmpl index 27386e87..7e10b254 100644 --- a/cmd/template/framework/files/makefile.tmpl +++ b/cmd/template/builder/files/makefile.tmpl @@ -39,12 +39,12 @@ templ-install: {{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} {{- if .OSCheck.UnixBased}} tailwind-install: - {{ if .OSCheck.linux }}@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-linux-x64 -o tailwindcss; fi{{- end }} - {{ if .OSCheck.darwin }}@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-macos-x64 -o tailwindcss; fi{{- end }} + {{ if .OSCheck.linux }}@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi{{- end }} + {{ if .OSCheck.darwin }}@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-x64 -o tailwindcss; fi{{- end }} @chmod +x tailwindcss {{- else }} tailwind-install: - @if not exist tailwindcss.exe powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.10/tailwindcss-windows-x64.exe' -OutFile 'tailwindcss.exe'"{{- end }} + @if not exist tailwindcss.exe powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-windows-x64.exe' -OutFile 'tailwindcss.exe'"{{- end }} {{- end }} build:{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} tailwind-install{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }} diff --git a/cmd/template/builder/main.go b/cmd/template/builder/main.go new file mode 100644 index 00000000..44c5e550 --- /dev/null +++ b/cmd/template/builder/main.go @@ -0,0 +1,17 @@ +package builder + +import _ "embed" + +//go:embed files/makefile.tmpl +var makeTemplate []byte + +//go:embed files/justfile.tmpl +var justTemplate []byte + +func MakeTemplate() []byte { + return makeTemplate +} + +func JustTemplate() []byte { + return justTemplate +} diff --git a/cmd/template/framework/files/README.md.tmpl b/cmd/template/framework/files/README.md.tmpl index 8e554ced..47e5ac4a 100644 --- a/cmd/template/framework/files/README.md.tmpl +++ b/cmd/template/framework/files/README.md.tmpl @@ -6,51 +6,51 @@ One Paragraph of project description goes here These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. -## MakeFile +## {{if eq .Builder "make"}}Makefile{{else if eq .Builder "just"}}Justfile{{end}} Run build make command with tests ```bash -make all +{{.Builder}} all ``` Build the application ```bash -make build +{{.Builder}} build ``` Run the application ```bash -make run +{{.Builder}} run ``` {{- if or .AdvancedOptions.docker (and (ne .DBDriver "none") (ne .DBDriver "sqlite")) }} Create DB container ```bash -make docker-run +{{.Builder}} docker-run ``` Shutdown DB Container ```bash -make docker-down +{{.Builder}} docker-down ``` DB Integrations Test: ```bash -make itest +{{.Builder}} itest ``` {{- end }} Live reload the application: ```bash -make watch +{{.Builder}} watch ``` Run the test suite: ```bash -make test +{{.Builder}} test ``` Clean up binary from the last build: ```bash -make clean +{{.Builder}} clean ``` diff --git a/cmd/template/framework/files/air.toml.tmpl b/cmd/template/framework/files/air.toml.tmpl index 271c01c2..960f882b 100644 --- a/cmd/template/framework/files/air.toml.tmpl +++ b/cmd/template/framework/files/air.toml.tmpl @@ -5,7 +5,7 @@ tmp_dir = "tmp" [build] args_bin = [] bin = {{if .OSCheck.UnixBased }}"./main"{{ else }}".\\main.exe"{{ end }} - cmd = "make build" + cmd = "{{.Builder}} build" delay = 1000 exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"] exclude_file = [] diff --git a/cmd/template/framework/files/main/fiber_main.go.tmpl b/cmd/template/framework/files/main/fiber_main.go.tmpl index a86d876f..52d253e4 100644 --- a/cmd/template/framework/files/main/fiber_main.go.tmpl +++ b/cmd/template/framework/files/main/fiber_main.go.tmpl @@ -23,6 +23,7 @@ func gracefulShutdown(fiberServer *server.FiberServer, done chan bool) { <-ctx.Done() log.Println("shutting down gracefully, press Ctrl+C again to force") + stop() // Allow Ctrl+C to force shutdown // The context is used to inform the server it has 5 seconds to finish // the request it is currently handling diff --git a/cmd/template/framework/files/main/main.go.tmpl b/cmd/template/framework/files/main/main.go.tmpl index ddcb061e..dbe97e31 100644 --- a/cmd/template/framework/files/main/main.go.tmpl +++ b/cmd/template/framework/files/main/main.go.tmpl @@ -21,6 +21,7 @@ func gracefulShutdown(apiServer *http.Server, done chan bool) { <-ctx.Done() log.Println("shutting down gracefully, press Ctrl+C again to force") + stop() // Allow Ctrl+C to force shutdown // The context is used to inform the server it has 5 seconds to finish // the request it is currently handling diff --git a/cmd/template/framework/main.go b/cmd/template/framework/main.go index 0611822b..2c44b7d7 100644 --- a/cmd/template/framework/main.go +++ b/cmd/template/framework/main.go @@ -15,18 +15,9 @@ var airTomlTemplate []byte //go:embed files/README.md.tmpl var readmeTemplate []byte -//go:embed files/makefile.tmpl -var makeTemplate []byte - //go:embed files/gitignore.tmpl var gitIgnoreTemplate []byte -// MakeTemplate returns a byte slice that represents -// the default Makefile template. -func MakeTemplate() []byte { - return makeTemplate -} - func GitIgnoreTemplate() []byte { return gitIgnoreTemplate } diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index 7ba4dd34..6266b62d 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -5,10 +5,12 @@ package utils import ( "bytes" "fmt" + "log" "os/exec" "regexp" "strings" + "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -47,14 +49,26 @@ func NonInteractiveCommand(use string, flagSet *pflag.FlagSet) string { return nonInteractiveCommand } +func RegisterStaticCompletions(cmd *cobra.Command, flag string, options []string) { + err := cmd.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return options, cobra.ShellCompDirectiveNoFileComp + }) + + if err != nil { + log.Printf("warning: could not register completion for --%s: %v", flag, err) + } +} + // ExecuteCmd provides a shorthand way to run a shell command func ExecuteCmd(name string, args []string, dir string) error { command := exec.Command(name, args...) command.Dir = dir var out bytes.Buffer + var stdErr bytes.Buffer command.Stdout = &out + command.Stderr = &stdErr if err := command.Run(); err != nil { - return err + return fmt.Errorf("%v\n%v", err, stdErr.String()) } return nil } diff --git a/docs/docs/advanced-flag/htmx-templ.md b/docs/docs/advanced-flag/htmx-templ.md index a1a61492..ad384fe0 100644 --- a/docs/docs/advanced-flag/htmx-templ.md +++ b/docs/docs/advanced-flag/htmx-templ.md @@ -22,28 +22,32 @@ web/ ## Usage - **Navigate to Project Directory:** + ```bash cd my-project ``` - **Install Templ CLI:** + ```bash go install github.com/a-h/templ/cmd/templ@latest ``` - **Generate Templ Function Files:** + ```bash templ generate ``` - **Start Server:** + ```bash make run ``` -## Makefile +## Makefile/justfile -Automates templ with Makefile entries, which are automatically created if the htmx advanced flag is used. +Automates templ with Makefile/justfile entries, which are automatically created if the htmx advanced flag is used. It detects if templ is installed or not and generates templates with the make build command. Both Windows and Unix-like OS are supported. @@ -51,7 +55,7 @@ Both Windows and Unix-like OS are supported. all: build templ-install: - @if ! command -v templ > /dev/null; then \ + if ! command -v templ > /dev/null; then \ read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ go install github.com/a-h/templ/cmd/templ@latest; \ @@ -66,9 +70,9 @@ templ-install: fi build: templ-install - @echo "Building..." - @templ generate - @go build -o main cmd/api/main.go + echo "Building..." + templ generate + go build -o main cmd/api/main.go ``` ## Templating diff --git a/docs/docs/advanced-flag/react-vite.md b/docs/docs/advanced-flag/react-vite.md index 01de8afe..e63c99f3 100644 --- a/docs/docs/advanced-flag/react-vite.md +++ b/docs/docs/advanced-flag/react-vite.md @@ -7,14 +7,14 @@ The React advanced flag can be combined with the Tailwind flag for enhanced styl ```bash / (Root) ├── frontend/ # React advanced flag. Excludes HTMX. -│ ├── .env # Frontend environment configuration +│ ├── .env # Frontend environment configuration. │ ├── node_modules/ # Node dependencies. │ ├── public/ │ │ ├── index.html │ │ └── favicon.ico │ ├── src/ # React source files. │ │ ├── App.tsx # Main React component. -│ │ ├── assets/ # React assets directory +│ │ ├── assets/ # React assets directory. │ │ │ └── logo.svg │ │ ├── components/ # React components directory. │ │ │ ├── Header.tsx @@ -36,34 +36,35 @@ The React advanced flag can be combined with the Tailwind flag for enhanced styl ## Usage - **Navigate to the `frontend` directory**: - First, navigate to the `frontend` directory where the React project resides. + First, navigate to the `frontend` directory where the React project resides. ```bash cd frontend ``` - **Install Dependencies**: - Use npm to install all necessary dependencies. + Use npm to install all necessary dependencies. ```bash npm install ``` - **Run the Development Server**: - Start the Vite development server for local development. This will launch a live-reloading server on a default port. + Start the Vite development server for local development. This will launch a live-reloading server on a default port. ```bash npm run dev ``` - You should now be able to access the React application by opening a browser and navigating to `http://localhost:5173`. - +You should now be able to access the React application by opening a browser and navigating to `http://localhost:5173`. You can extend the `vite.config.ts` to include additional configurations as needed, such as adding plugins for optimizing the build process, enabling TypeScript support, or configuring Tailwind CSS. -## Makefile +## Makefile/justfile + +The make/just run target will start the Go server in the backend, install frontend dependencies, and run the Vite development server for the frontend. -The make run target will start the Go server in the backend, install frontend dependencies, and run the Vite development server for the frontend. +# Makefile ```bash run: @@ -72,6 +73,16 @@ run: @npm run dev --prefix ./frontend ``` +# justfile + +```bash +run: + go run cmd/api/main.go & + npm install --prefix ./frontend + npm run dev --prefix ./frontend + +``` + After running this command, you can verify the connection between the frontend and backend by checking the console. You can also fetch data from the backend to test the integration.  @@ -197,7 +208,11 @@ services: volumes: - psql_volume_bp:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "sh -c 'pg_isready -U ${BLUEPRINT_DB_USERNAME} -d ${BLUEPRINT_DB_DATABASE}'"] + test: + [ + "CMD-SHELL", + "sh -c 'pg_isready -U ${BLUEPRINT_DB_USERNAME} -d ${BLUEPRINT_DB_DATABASE}'", + ] interval: 5s timeout: 5s retries: 3 diff --git a/docs/docs/advanced-flag/tailwind.md b/docs/docs/advanced-flag/tailwind.md index 0d2e4b66..6b7c2831 100644 --- a/docs/docs/advanced-flag/tailwind.md +++ b/docs/docs/advanced-flag/tailwind.md @@ -3,6 +3,7 @@ Tailwind is closely coupled with the advanced HTMX flag, and HTMX will be automa We do not introduce outside dependencies automatically, and you need compile output.css (file is empty by default) with the Tailwind CLI tool. The project tree would look like this: + ```bash / (Root) ├── cmd/ @@ -29,18 +30,18 @@ The project tree would look like this: │ └── server.go ├── go.mod ├── go.sum -├── Makefile -├── README.md -└── tailwind.config.js +├── Makefile/justfile +└── README.md ``` ## Standalone Tailwind CLI The The idea is to avoid using Node.js and npm to build output.css. -The Makefile will have entries for downloading and compiling CSS. It will automatically detect the OS and download the latest release from the [official repository](https://github.com/tailwindlabs/tailwindcss/releases). +The Makefile/justfile will have entries for downloading and compiling CSS. It will automatically detect the OS and download the latest release from the [official repository](https://github.com/tailwindlabs/tailwindcss/releases). ## Linux Makefile Example + ```bash all: build templ-install: @@ -75,5 +76,3 @@ By default, simple CSS examples are included in the codebase. Update base.templ and hello.templ, then rerun templ generate to see the changes at the `localhost:PORT/web` endpoint.  - - diff --git a/docs/docs/advanced-flag/websocket.md b/docs/docs/advanced-flag/websocket.md index c7bea3ad..aaafb425 100644 --- a/docs/docs/advanced-flag/websocket.md +++ b/docs/docs/advanced-flag/websocket.md @@ -1,4 +1,4 @@ -A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible project is. +A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible a project is. ### Code Implementation diff --git a/docs/docs/blueprint-core/db-drivers.md b/docs/docs/blueprint-core/db-drivers.md index f34c72d0..ac007e8e 100644 --- a/docs/docs/blueprint-core/db-drivers.md +++ b/docs/docs/blueprint-core/db-drivers.md @@ -4,7 +4,7 @@ To extend the project with database functionality, users can choose from a varie 2. [Mysql](https://github.com/go-sql-driver/mysql): Enables seamless integration with MySQL databases. 3. [Postgres](https://github.com/jackc/pgx/): Facilitates connectivity to PostgreSQL databases. 4. [Redis](https://github.com/redis/go-redis): Provides tools for connecting and interacting with Redis. -5. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database. and interacting with Redis +5. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database. 6. [ScyllaDB](https://github.com/scylladb/gocql): Facilitates connectivity to ScyllaDB databases. ## Updated Project Structure @@ -26,7 +26,7 @@ Integrating a database adds a new layer to the project structure, primarily in t │ └── server.go ├── go.mod ├── go.sum -├── Makefile +├── Makefile/justfile └── README.md ``` @@ -36,11 +36,10 @@ Users can select the desired database driver based on their project's specific n ## Integration Tests for Database Operations -For all the database drivers but the `Sqlite`, integration tests are automatically generated to ensure that the database connection is working correctly. It uses [Testcontainers for Go](https://golang.testcontainers.org/) to spin up a containerized instance of the database server, run the tests, and then tear down the container. +For all the database drivers but `Sqlite`, integration tests are automatically generated to ensure that the database connection is working correctly. It uses [Testcontainers for Go](https://golang.testcontainers.org/) to spin up a containerized instance of the database server, run the tests, and then tear down the container. [Testcontainers for Go](https://golang.testcontainers.org/) is a Go package that makes it simple to create and clean up container-based dependencies for automated integration/smoke tests. The clean, easy-to-use API enables developers to programmatically define containers that should be run as part of a test and clean up those resources when the test is done. - ### Requirements You need a container runtime installed on your machine. Testcontainers supports Docker and any other container runtime that implements the Docker APIs. @@ -59,7 +58,7 @@ Go to the `internal/database` directory and run the following command: go test -v ``` -or just run the following command from the root directory: +Or, just run the following command from the root directory: ```bash make itest diff --git a/docs/docs/blueprint-core/frameworks.md b/docs/docs/blueprint-core/frameworks.md index 00aa84df..3ec8d961 100644 --- a/docs/docs/blueprint-core/frameworks.md +++ b/docs/docs/blueprint-core/frameworks.md @@ -1,4 +1,4 @@ -Created project can utilizes several Go web frameworks to handle HTTP routing and server functionality. The chosen frameworks are: +Created projects can utilize several Go web frameworks to handle HTTP routing and server functionality. The chosen frameworks are: 1. [**Chi**](https://github.com/go-chi/chi): Lightweight and flexible router for building Go HTTP services. 2. [**Echo**](https://github.com/labstack/echo): High-performance, extensible, minimalist Go web framework. @@ -23,6 +23,6 @@ The project is structured with a simple layout, focusing on the cmd, internal, a │ └── server.go ├── go.mod ├── go.sum -├── Makefile +├── Makefile/justfile └── README.md ``` diff --git a/docs/docs/creating-project/air.md b/docs/docs/creating-project/air.md index 7d0ea4f6..c910ee6e 100644 --- a/docs/docs/creating-project/air.md +++ b/docs/docs/creating-project/air.md @@ -2,7 +2,7 @@ [Air](https://github.com/cosmtrek/air) is a live-reloading utility designed to enhance the development experience by automatically rebuilding and restarting your Go application whenever changes are detected in the source code. -The Makefile provided in the project repository includes a command make watch, which triggers Air to monitor file changes and initiate rebuilds and restarts as necessary. Additionally, if Air is not installed on your machine, the Makefile provides an option to install it automatically. +The Makefile/justfil provided in the project repository includes a command make watch, which triggers Air to monitor file changes and initiate rebuilds and restarts as necessary. Additionally, if Air is not installed on your machine, the Makefile provides an option to install it automatically. Air's `.air.toml` configuration file allows customization of various aspects of its behavior. @@ -11,8 +11,8 @@ Air's `.air.toml` configuration file allows customization of various aspects of ```bash make watch - __ _ ___ - / /\ | | | |_) + __ _ ___ + / /\ | | | |_) /_/--\ |_| |_| \_ v1.51.0, built with Go go1.22.0 mkdir /home/ujstor/code/blueprint-version-test/ws-test4/tmp @@ -48,4 +48,4 @@ make[1]: Leaving directory '/home/ujstor/code/blueprint-version-test/ws-test4' running... ``` -Integrating Air into your development workflow alongside the provided Makefile enables a smooth and efficient process for building, testing, and running your Go applications. With automatic live-reloading, you can focus more on coding and less on manual build and restart steps. +Integrating Air into your development workflow alongside the provided Makefile/justfile enables a smooth and efficient process for building, testing, and running your Go applications. With automatic live-reloading, you can focus more on coding and less on manual build and restart steps. diff --git a/docs/docs/creating-project/justfile.md b/docs/docs/creating-project/justfile.md new file mode 100644 index 00000000..aaa015cf --- /dev/null +++ b/docs/docs/creating-project/justfile.md @@ -0,0 +1,75 @@ +# Justfile Project Management + +`just` is an alternative task runner to Make, focused on simplicity and ease of use with a more modern syntax. This project includes a `Justfile` that mirrors much of the Makefile functionality for managing, building, and testing a Go application, with support for optional frontend tooling like HTMX and Tailwind CSS. + +## Overview + +The `justfile` provides shorthand commands for common development tasks, making it easy to: + +- Build and run the project +- Install necessary tools (`templ`, `tailwindcss`, etc.) +- Manage frontend assets +- Run tests and clean the build environment +- Use Docker for database containers +- Enable live reload for development + +## Recipes + +### `all` + +Builds the Go application and runs tests. Equivalent to running `just build` followed by `just test`. + +### `templ-install` + +Installs the Go-based templating tool `templ`, using OS-specific logic: + +- **Unix-based systems**: Uses shell commands to check and install. +- **Windows**: Uses PowerShell to install if not present. + +### `tailwind-install` + +Downloads and installs the correct version of `tailwindcss`: + +- **Linux/macOS**: Downloads the appropriate binary based on OS. +- **Windows**: Uses PowerShell to fetch the executable. + +### `build` + +Builds the Go application and generates frontend assets: + +- Uses `templ` for template generation. +- Compiles Tailwind CSS if enabled. + +### `run` + +Runs the main Go application from `cmd/api/main.go`. If the React flag is active, it also runs `npm install` and `npm run dev`. + +### `docker-run` and `docker-down` + +Manages a Docker container for the database: + +- **Unix**: Prefers Docker Compose V2, falls back to V1. +- **Windows**: Uses Docker Compose without fallback logic. + +### `test` + +Runs unit tests with `go test`. + +### `itest` + +Executes integration tests for projects that use databases other than SQLite. + +### `clean` + +Removes the built binary (`main` or `main.exe`, depending on platform). + +### `watch` + +Starts a development server with live reload using the `air` tool: + +- **Unix**: Checks for `air` and installs if missing. +- **Windows**: Uses PowerShell to handle `air` setup and execution. + +--- + +For developers who prefer `just` over `make`, this `Justfile` offers a clean and minimal way to manage the entire Go project lifecycle. diff --git a/docs/docs/creating-project/project-init.md b/docs/docs/creating-project/project-init.md index 9eae177c..6ad0b23c 100644 --- a/docs/docs/creating-project/project-init.md +++ b/docs/docs/creating-project/project-init.md @@ -39,7 +39,7 @@ To recreate the project using the same configuration semi-interactively, use the ```bash go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced ``` -This approach opens interactive mode only for advanced features, which allow you to choose the one or combination of available features. +This approach opens interactive mode only for advanced features, which allows you to choose the one or combination of available features.  diff --git a/docs/docs/endpoints-test/mongo.md b/docs/docs/endpoints-test/mongo.md index 15557f30..1c81aa9c 100644 --- a/docs/docs/endpoints-test/mongo.md +++ b/docs/docs/endpoints-test/mongo.md @@ -44,4 +44,4 @@ func (s *service) Health() map[string]string { ## Note -MongoDB does not support advanced health check functions like SQL databases or Redis. Implementation is basic, providing only a simple ping response to indicate if the server is reachable and DB connection healthy. +MongoDB does not support advanced health check functions like SQL databases or Redis. The implementation is basic, providing only a simple ping response to indicate if the server is reachable and DB connection healthy. diff --git a/docs/docs/index.md b/docs/docs/index.md index 39e0fd00..c0f3b90a 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -2,11 +2,11 @@ hide: - toc --- + ## Go Blueprint - Ultimate Golang Blueprint Library  - Powerful CLI tool designed to streamline the process of creating Go projects with a robust and standardized structure. Not only does Go Blueprint facilitate project initialization, but it also offers seamless integration with popular Go frameworks, allowing you to focus on your application's code from the very beginning. ## Why Choose Go Blueprint? @@ -33,8 +33,8 @@ Here's an overview of the project structure created by Go Blueprint when all opt │ ├── api/ │ │ └── main.go # Main file for starting the server. │ └── web/ -│ ├── styles/ # only for generating css will not be served public -│ │ └── input.css # Tailwind input file for compiling output.css with CLI when HTMX is used +│ ├── styles/ # Only for generating css will not be served public. +│ │ └── input.css # Tailwind input file for compiling output.css with CLI when HTMX is used. │ ├── assets/ │ │ ├── css/ │ │ │ └── output.css # Generated CSS file. @@ -53,7 +53,7 @@ Here's an overview of the project structure created by Go Blueprint when all opt │ │ └── favicon.ico │ ├── src/ # React source files. │ │ ├── App.tsx # Main React component. -│ │ ├── assets/ # React assets directory +│ │ ├── assets/ # React assets directory. │ │ │ └── logo.svg │ │ ├── components/ # React components directory. │ │ │ ├── Header.tsx @@ -86,8 +86,7 @@ Here's an overview of the project structure created by Go Blueprint when all opt ├── go.mod # Go module file for managing dependencies. ├── .goreleaser.yml # Configuration file for GoReleaser, a tool for building and releasing binaries. ├── go.sum # Go module file containing checksums for dependencies. -├── Makefile # Makefile for defining and running commands. -├── tailwind.config.js # Tailwind CSS configuration file for HTMX. +├── Makefile/justfile # Makefile for defining and running commands. └── README.md # Project's README file containing essential information about the project. ``` diff --git a/docs/docs/installation.md b/docs/docs/installation.md index 852a103f..de058c82 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -7,7 +7,7 @@ Go-Blueprint provides a convenient CLI tool to effortlessly set up your Go proje ## Binary Installation -To install the Go-Blueprint CLI tool as a binary, Run the following command: +To install the Go-Blueprint CLI tool as a binary, run the following command: ```sh go install github.com/melkeydev/go-blueprint@latest @@ -15,7 +15,7 @@ go install github.com/melkeydev/go-blueprint@latest This command installs the Go-Blueprint binary, automatically binding it to your `$GOPATH`. -> if you’re using Zsh, you’ll need to add it manually to `~/.zshrc`. +> If you’re using Zsh, you’ll need to add it manually to `~/.zshrc`. > After running the installation command, you need to update your `PATH` environment variable. To do this, you need to find out the correct `GOPATH` for your system. You can do this by running the following command: > Check your `GOPATH` diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index b9ece5be..0168a439 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -18,7 +18,7 @@ theme: - navigation.sections - navigation.footer - toc.flow - palette: + palette: - scheme: default toggle: icon: material/brightness-7 @@ -33,44 +33,45 @@ nav: - Installation: installation.md - Blueprint UI: blueprint-ui.md - Project creation & default config: - - Project init: creating-project/project-init.md - - Makefile: creating-project/makefile.md - - Air: creating-project/air.md + - Project init: creating-project/project-init.md + - Makefile: creating-project/makefile.md + - Justfile: creating-project/justfile.md + - Air: creating-project/air.md - Blueprint Core: - - Frameworks: blueprint-core/frameworks.md - - DB Drivers: blueprint-core/db-drivers.md + - Frameworks: blueprint-core/frameworks.md + - DB Drivers: blueprint-core/db-drivers.md - Advanced Flag: - - AF Usage: advanced-flag/advanced-flag.md - - HTMX and Templ: advanced-flag/htmx-templ.md - - Tailwind CSS: advanced-flag/tailwind.md - - GoReleaser & GoTest CI: advanced-flag/goreleaser.md - - Websocket: advanced-flag/websocket.md - - Docker: advanced-flag/docker.md - - React & Vite (TypeScript): advanced-flag/react-vite.md - - Testing endpoints: - - Server: endpoints-test/server.md - - DB Health Endpoints: - - SQL DBs: endpoints-test/sql.md - - Redis: endpoints-test/redis.md - - MongoDB: endpoints-test/mongo.md - - ScyllaDB: endpoints-test/scylladb.md - - Websocket: endpoints-test/websocket.md - - Web Endpoint: endpoints-test/web.md + - AF Usage: advanced-flag/advanced-flag.md + - HTMX and Templ: advanced-flag/htmx-templ.md + - Tailwind CSS: advanced-flag/tailwind.md + - GoReleaser & GoTest CI: advanced-flag/goreleaser.md + - Websocket: advanced-flag/websocket.md + - Docker: advanced-flag/docker.md + - React & Vite (TypeScript): advanced-flag/react-vite.md + - Testing endpoints: + - Server: endpoints-test/server.md + - DB Health Endpoints: + - SQL DBs: endpoints-test/sql.md + - Redis: endpoints-test/redis.md + - MongoDB: endpoints-test/mongo.md + - ScyllaDB: endpoints-test/scylladb.md + - Websocket: endpoints-test/websocket.md + - Web Endpoint: endpoints-test/web.md extra: - social: - - icon: fontawesome/brands/discord - link: https://discord.com/invite/HHZMSCu - name: Discord - - icon: fontawesome/brands/twitch - link: https://www.twitch.tv/melkey - name: Twitch - - icon: fontawesome/brands/youtube - link: https://www.youtube.com/@MelkeyDev - name: YouTube - - icon: fontawesome/brands/twitter - link: https://x.com/MelkeyDev - name: Twitter - generator: false + social: + - icon: fontawesome/brands/discord + link: https://discord.com/invite/HHZMSCu + name: Discord + - icon: fontawesome/brands/twitch + link: https://www.twitch.tv/melkey + name: Twitch + - icon: fontawesome/brands/youtube + link: https://www.youtube.com/@MelkeyDev + name: YouTube + - icon: fontawesome/brands/twitter + link: https://x.com/MelkeyDev + name: Twitter + generator: false copyright: Copyright © 2025 Melkey diff --git a/go.mod b/go.mod index 88501fc4..200962c4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/melkeydev/go-blueprint -go 1.22.4 +go 1.23.0 require ( github.com/charmbracelet/bubbles v0.16.1 diff --git a/public/build.gif b/public/build.gif new file mode 100644 index 00000000..97778bce Binary files /dev/null and b/public/build.gif differ