Copy over environment.go and generate .env file in starter

This commit is contained in:
Achim Rohn
2025-09-03 00:32:45 +02:00
parent 5f0a1872a5
commit 7c41bd3d35
5 changed files with 118 additions and 99 deletions
+3
View File
@@ -0,0 +1,3 @@
.env
.idea/
tmp/
-80
View File
@@ -1,80 +0,0 @@
package main
import (
"errors"
"ersteller-lib/starter/env"
"fmt"
"os"
"path/filepath"
"strings"
)
// findRepoRoot walks up from the current working directory until it finds a go.mod file.
// It returns the directory containing go.mod, or an error if not found.
func findRepoRoot() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
curr := wd
for {
if _, err := os.Stat(filepath.Join(curr, "go.mod")); err == nil {
return curr, nil
}
parent := filepath.Dir(curr)
if parent == curr {
break
}
curr = parent
}
return "", errors.New("could not locate repository root (go.mod not found in any parent directory)")
}
func main() {
root, err := findRepoRoot()
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
envPath := filepath.Join(root, ".env")
if _, err := os.Stat(envPath); err == nil {
fmt.Println(".env already exists at:", envPath)
fmt.Println("No changes made. Delete or move the existing .env to regenerate.")
return
}
// Build .env content dynamically from keys exposed by env package
// so we don't duplicate the list here.
keys := env.EnvKeys()
builder := &strings.Builder{}
fmt.Fprintln(builder, "# Environment configuration for Salezenify")
fmt.Fprintln(builder, "# Generated by cli/generate_env.go")
fmt.Fprintln(builder, "# Fill in the appropriate values for your environment.")
fmt.Fprintln(builder)
// Optional defaults can be set here; leave blank for most keys to avoid assumptions.
defaults := map[string]string{
"REPOSITORY_TYPE": "postgres",
}
for _, k := range keys {
v := defaults[k]
if v == "" {
fmt.Fprintf(builder, "%s=\n", k)
} else {
fmt.Fprintf(builder, "%s=%s\n", k, v)
}
}
content := builder.String()
if err := os.WriteFile(envPath, []byte(content), 0600); err != nil {
fmt.Println("Failed to write .env:", err)
os.Exit(1)
}
fmt.Println(".env file created at:", envPath)
fmt.Println("Review and update the values as needed.")
}
+28 -11
View File
@@ -2,6 +2,8 @@ package create
import ( import (
. "ersteller-lib" . "ersteller-lib"
"ersteller-lib/starter/env"
"fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
@@ -22,6 +24,7 @@ type Params struct {
ProjectDir string ProjectDir string
ModuleName string ModuleName string
GoPath string GoPath string
OverwriteEnv bool
} }
type StarterCreator struct { type StarterCreator struct {
@@ -71,6 +74,7 @@ func (s StarterCreator) Create() {
// Write to <ProjectDir>/main.go // Write to <ProjectDir>/main.go
targetPath := filepath.Join(s.params.ProjectDir, "main.go") targetPath := filepath.Join(s.params.ProjectDir, "main.go")
content = s.replaceImports(content)
must(os.WriteFile(targetPath, content, 0o644)) must(os.WriteFile(targetPath, content, 0o644))
log.Printf("StarterCreator.Create: wrote starter main.go to %s", targetPath) log.Printf("StarterCreator.Create: wrote starter main.go to %s", targetPath)
@@ -91,6 +95,24 @@ func (s StarterCreator) Create() {
if s.params.DbType == DataBaseTypeSqlite { if s.params.DbType == DataBaseTypeSqlite {
s.executeDbPush() s.executeDbPush()
} }
s.copyFile("../.gitignore", ".gitignore")
s.createEnvironment()
}
func (s StarterCreator) createEnvironment() {
if err := os.MkdirAll(s.params.ProjectDir+"/env", 0o755); err != nil {
log.Printf("StarterCreator.Create: failed to create env target directory%v", err)
return
}
//s.copyFile("../env/environment.go", "env/environment.go")
content, err := os.ReadFile(filepath.Join(s.thisDir, "../env/environment.go"))
must(err)
must(os.WriteFile(filepath.Join(s.params.ProjectDir, "env/environment.go"), content, 0o644))
must(env.GenerateEnvFile(s.params.ProjectDir, s.params.OverwriteEnv))
} }
func (s StarterCreator) executeDbPush() { func (s StarterCreator) executeDbPush() {
@@ -119,17 +141,6 @@ func (s StarterCreator) executeDbPush() {
func (s StarterCreator) copyFile(src string, dst string) { func (s StarterCreator) copyFile(src string, dst string) {
content, err := os.ReadFile(filepath.Join(s.thisDir, src)) content, err := os.ReadFile(filepath.Join(s.thisDir, src))
must(err) must(err)
// If we are copying the Prisma schema and the target DB is sqlite,
// replace the datasource block accordingly.
if dst == "schema.prisma" && s.params.DbType == DataBaseTypeSqlite {
pgBlock := "datasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n"
sqliteBlock := "datasource db {\n provider = \"sqlite\"\n url = \"file:./db/sqlite.db\"\n}\n"
contentStr := string(content)
contentStr = strings.Replace(contentStr, pgBlock, sqliteBlock, 1)
content = []byte(contentStr)
}
must(os.WriteFile(filepath.Join(s.params.ProjectDir, dst), content, 0o644)) must(os.WriteFile(filepath.Join(s.params.ProjectDir, dst), content, 0o644))
} }
@@ -187,6 +198,12 @@ func (s StarterCreator) executeGetPrismaClient() {
must(cmd.Run()) must(cmd.Run())
} }
func (s StarterCreator) replaceImports(content []byte) []byte {
contentString := string(content)
contentString = strings.ReplaceAll(contentString, "\"ersteller-lib/starter/env\"", fmt.Sprint("\"", s.params.ModuleName, "/env\""))
return []byte(contentString)
}
func must(err error) { func must(err error) {
if err != nil { if err != nil {
panic(err) panic(err)
+79
View File
@@ -2,7 +2,9 @@ package env
import ( import (
. "ersteller-lib" . "ersteller-lib"
"fmt"
"os" "os"
"path/filepath"
"github.com/joho/godotenv" "github.com/joho/godotenv"
) )
@@ -100,3 +102,80 @@ func EnvKeys() []string {
EnvKeyKeycloakClientSecret, EnvKeyKeycloakClientSecret,
} }
} }
// GenerateEnvFile creates a .env file template with all required environment variables
// from the EnvKeys function. The file will contain comments and default values where appropriate.
func GenerateEnvFile(rootPath string, overwrite bool) error {
envPath := filepath.Join(rootPath, ".env")
Debug("envPath:", envPath)
if !overwrite {
if _, err := os.Stat(envPath); err == nil {
fmt.Println(".env already exists at:", envPath)
fmt.Println("No changes made. Delete or move the existing .env to regenerate.")
return fmt.Errorf(".env already exists at: %s", envPath)
}
}
file, err := os.Create(envPath)
if err != nil {
return fmt.Errorf("failed to create .env file: %w", err)
}
defer file.Close()
// Write header comment
_, err = file.WriteString("# Environment Variables Configuration\n")
if err != nil {
return fmt.Errorf("failed to write to .env file: %w", err)
}
_, err = file.WriteString("# Generated from EnvKeys function\n\n")
if err != nil {
return fmt.Errorf("failed to write to .env file: %w", err)
}
// Get all environment keys
keys := EnvKeys()
// Define default values and comments for specific keys
defaults := map[string]string{
EnvKeyRepositoryType: "postgres",
EnvKeyIsLocal: "false",
EnvKeyIsDev: "false",
}
comments := map[string]string{
EnvKeyRepositoryType: "# Repository type (postgres, sqlite, etc.)",
EnvKeyDatabaseURL: "# Database connection URL",
EnvKeySessionSecret: "# Secret key for session management",
EnvKeyBaseURL: "# Base URL of the application",
EnvKeyIsLocal: "# Set to true for local development",
EnvKeyIsDev: "# Set to true for development mode",
EnvKeyGoogleClientID: "# Google OAuth client ID",
EnvKeyGoogleClientSecret: "# Google OAuth client secret",
EnvKeyGoogleRedirectURL: "# Google OAuth redirect URL",
EnvKeyKeycloakDiscoveryURL: "# Keycloak discovery URL",
EnvKeyKeycloakClientID: "# Keycloak client ID",
EnvKeyKeycloakClientSecret: "# Keycloak client secret",
}
// Write each environment variable
for _, key := range keys {
// Write comment if available
if comment, exists := comments[key]; exists {
_, err = file.WriteString(comment + "\n")
if err != nil {
return fmt.Errorf("failed to write to .env file: %w", err)
}
}
// Write the environment variable with default value if available
if defaultValue, exists := defaults[key]; exists {
_, err = file.WriteString(fmt.Sprintf("%s=%s\n", key, defaultValue))
} else {
_, err = file.WriteString(fmt.Sprintf("%s=\n", key))
}
if err != nil {
return fmt.Errorf("failed to write to .env file: %w", err)
}
}
return nil
}
+4 -4
View File
@@ -2,6 +2,7 @@ package main
import ( import (
. "ersteller-lib" . "ersteller-lib"
"ersteller-lib/starter/env"
"log" "log"
"net/http" "net/http"
) )
@@ -10,10 +11,9 @@ func main() {
GlobalI18n = GlobalI18nImplementation{} GlobalI18n = GlobalI18nImplementation{}
server := NewHtmxServer() server := NewHtmxServer()
// Path to the SQLite database environment := env.LoadEnvironment()
dbPath := "db/sqlite.db"
// Create database connection db, err := CreatePostgresConnpool(environment.DatabaseUrl)
db, err := CreateSQLiteConnpool(dbPath)
if err != nil { if err != nil {
Error("Failed to create database connection:", err) Error("Failed to create database connection:", err)
panic(err) panic(err)