Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 129 additions & 20 deletions backend/gen_microservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,155 @@ package main
import (
"archive/zip"
"bytes"
"errors"
"fmt"
"log"
)

func GenerateMicroservice(request CreateProjectRequest) (*bytes.Buffer, error) {
// Implementation for generating a microservice project based on input
// generate a zip file in memory
// MicroserviceGenerator implements Generator for the "microservice" project type.
//
// Generated layout:
//
// <name>/
// ├── cmd/<name>/main.go
// ├── internal/
// │ ├── handler/handler.go
// │ └── service/service.go
// ├── go.mod
// ├── README.md
// └── Dockerfile (optional)
type MicroserviceGenerator struct{}

func (g *MicroserviceGenerator) Generate(request CreateProjectRequest) (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
zipWriter := zip.NewWriter(buf)

// Create a folder with the project name and write files inside it
folderName := request.Name
if folderName == "" {
folderName = "project"
folderName = "myservice"
}

// Example: add a README.md file inside the folder
readmeContent := fmt.Sprintf("# %s\n\n%s", request.Name, request.Description)
readmeFile, err := zipWriter.Create(fmt.Sprintf("%s/README.md", folderName))
if err != nil {
log.Printf("[ERROR] Failed to create file in zip: %v", err)
err = errors.New("failed to create file in zip")
// README.md
readmeContent := fmt.Sprintf("# %s\n\n%s", folderName, request.Description)
if err := addToZip(zipWriter, fmt.Sprintf("%s/README.md", folderName), []byte(readmeContent)); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}
_, err = readmeFile.Write([]byte(readmeContent))

// go.mod
gomodContent, err := GenerateGoModV2(request)
if err != nil {
log.Printf("[ERROR] Failed to write to zip: %v", err)
err = errors.New("failed to write to zip file")
log.Printf("[ERROR] Failed to generate go.mod: %v", err)
return nil, fmt.Errorf("failed to generate go.mod: %w", err)
}
if err := addToZip(zipWriter, fmt.Sprintf("%s/go.mod", folderName), gomodContent); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// Add more files as needed based on request
err = zipWriter.Close()
if err != nil {
log.Printf("[ERROR] Failed to close zip writer: %v", err)
err = errors.New("failed to finalize zip file")
// cmd/<name>/main.go
mainContent := generateMicroserviceMain(request.ModuleName)
if err := addToZip(zipWriter, fmt.Sprintf("%s/cmd/%s/main.go", folderName, folderName), mainContent); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// internal/handler/handler.go
if err := addToZip(zipWriter, fmt.Sprintf("%s/internal/handler/handler.go", folderName), microserviceHandlerStub()); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// internal/service/service.go
if err := addToZip(zipWriter, fmt.Sprintf("%s/internal/service/service.go", folderName), microserviceServiceStub()); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// Addons
for addonType, addons := range request.Addons {
gen, ok := addonRegistry[addonType]
if !ok || len(addons) == 0 {
continue
}
if err := gen.Generate(folderName, addons, zipWriter); err != nil {
log.Printf("[ERROR] Failed to generate %s addon: %v", addonType, err)
return nil, fmt.Errorf("failed to generate %s addon: %w", addonType, err)
}
}

// .gitignore
if err := addToZip(zipWriter, fmt.Sprintf("%s/.gitignore", folderName), GenerateGitignore()); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// Dockerfile (optional)
if request.DockerSupport {
if err := addToZip(zipWriter, fmt.Sprintf("%s/Dockerfile", folderName), GenerateDockerfile(request)); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}
}

if err := zipWriter.Close(); err != nil {
log.Printf("[ERROR] Failed to close zip writer: %v", err)
return nil, fmt.Errorf("failed to finalize zip: %w", err)
}
return buf, nil
}

func generateMicroserviceMain(moduleName string) []byte {
return []byte(fmt.Sprintf(`// Code generated by go-initializer. DO NOT EDIT.
package main

import (
"log"
"net/http"

"%s/internal/handler"
)

func main() {
h := handler.New()
http.HandleFunc("/healthz", h.Healthz)
log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
`, moduleName))
}

func microserviceHandlerStub() []byte {
return []byte(`// Code generated by go-initializer. DO NOT EDIT.
package handler

import "net/http"

// Handler holds application dependencies.
type Handler struct{}

// New creates a new Handler.
func New() *Handler {
return &Handler{}
}

// Healthz handles health check requests.
func (h *Handler) Healthz(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
`)
}

func microserviceServiceStub() []byte {
return []byte(`// Code generated by go-initializer. DO NOT EDIT.
package service

// Service holds business logic.
type Service struct{}

// New creates a new Service.
func New() *Service {
return &Service{}
}
`)
}
179 changes: 60 additions & 119 deletions backend/gen_simple_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package main
import (
"archive/zip"
"bytes"
"errors"
"fmt"
"log"
)

// myproject/
// ├── cmd/
// │ └── myproject/
// │ └── main.go
// ├── internal/ # Business logic
// │ └── service.go
// ├── go.mod
// └── README.md
func GenerateSimpleProject(request CreateProjectRequest) (*bytes.Buffer, error) {
// SimpleProjectGenerator implements Generator for the "simple-project" project type.
//
// Generated layout:
//
// <name>/
// ├── cmd/<name>/main.go
// ├── internal/service.go
// ├── go.mod
// ├── README.md
// └── Dockerfile (optional)
type SimpleProjectGenerator struct{}

func (g *SimpleProjectGenerator) Generate(request CreateProjectRequest) (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
zipWriter := zip.NewWriter(buf)

Expand All @@ -25,139 +28,77 @@ func GenerateSimpleProject(request CreateProjectRequest) (*bytes.Buffer, error)
folderName = "myproject"
}

// 1. README.md
// README.md
readmeContent := fmt.Sprintf("# %s\n\n%s", folderName, request.Description)
readmeFile, err := zipWriter.Create(fmt.Sprintf("%s/README.md", folderName))
if err != nil {
log.Printf("[ERROR] Failed to create README.md in zip: %v", err)
return nil, errors.New("failed to create README.md in zip")
}
_, err = readmeFile.Write([]byte(readmeContent))
if err != nil {
log.Printf("[ERROR] Failed to write README.md: %v", err)
return nil, errors.New("failed to write README.md")
if err := addToZip(zipWriter, fmt.Sprintf("%s/README.md", folderName), []byte(readmeContent)); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// 2. go.mod (minimal content)
// go.mod
gomodContent, err := GenerateGoModV2(request)
if err != nil {
log.Printf("[ERROR] Failed to generate go.mod content: %v", err)
return nil, errors.New("failed to generate go.mod content")
}
gomodFile, err := zipWriter.Create(fmt.Sprintf("%s/go.mod", folderName))
if err != nil {
log.Printf("[ERROR] Failed to create go.mod in zip: %v", err)
return nil, errors.New("failed to create go.mod in zip")
log.Printf("[ERROR] Failed to generate go.mod: %v", err)
return nil, fmt.Errorf("failed to generate go.mod: %w", err)
}
_, err = gomodFile.Write([]byte(gomodContent))
if err != nil {
log.Printf("[ERROR] Failed to write go.mod: %v", err)
return nil, errors.New("failed to write go.mod")
if err := addToZip(zipWriter, fmt.Sprintf("%s/go.mod", folderName), gomodContent); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// 3. cmd/myproject/main.go using GenerateMain
mainGoPath := fmt.Sprintf("%s/cmd/%s/main.go", folderName, folderName)
mainGoFile, err := zipWriter.Create(mainGoPath)
if err != nil {
log.Printf("[ERROR] Failed to create main.go in zip: %v", err)
return nil, errors.New("failed to create main.go in zip")
}
// cmd/<name>/main.go
mainGoContent, err := GenerateMainContent()
if err != nil {
log.Printf("[ERROR] Failed to generate main.go content: %v", err)
return nil, errors.New("failed to generate main.go content")
log.Printf("[ERROR] Failed to generate main.go: %v", err)
return nil, fmt.Errorf("failed to generate main.go: %w", err)
}
_, err = mainGoFile.Write(mainGoContent)
if err != nil {
log.Printf("[ERROR] Failed to write main.go: %v", err)
return nil, errors.New("failed to write main.go")
if err := addToZip(zipWriter, fmt.Sprintf("%s/cmd/%s/main.go", folderName, folderName), mainGoContent); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// check addons and include if any
if len(request.Addons) > 0 {
for addonType, addons := range request.Addons {
if addonType == "logging" {
}
if addonType == "database" {
if len(addons) == 0 {
continue
}
dbPath := fmt.Sprintf("%s/internal/database/database.go", folderName)
dbFile, err := zipWriter.Create(dbPath)
if err != nil {
log.Printf("[ERROR] Failed to create database.go in zip: %v", err)
return nil, errors.New("failed to create database.go in zip")
}
dbContent, err := GenerateDatabaseAddon(addons)
if err != nil {
log.Printf("[ERROR] Failed to generate database.go content: %v", err)
return nil, errors.New("failed to generate database.go content")
}
_, err = dbFile.Write(dbContent)
if err != nil {
log.Printf("[ERROR] Failed to write database.go: %v", err)
return nil, errors.New("failed to write database.go")
}
}
if addonType == "cache" {
if len(addons) == 0 {
continue
}
cachePath := fmt.Sprintf("%s/internal/cache/cache.go", folderName)
cacheFile, err := zipWriter.Create(cachePath)
if err != nil {
log.Printf("[ERROR] Failed to create cache.go in zip: %v", err)
return nil, errors.New("failed to create cache.go in zip")
}
cacheContent, err := GenerateCacheAddon(addons)
if err != nil {
log.Printf("[ERROR] Failed to generate cache.go content: %v", err)
return nil, errors.New("failed to generate cache.go content")
}
_, err = cacheFile.Write(cacheContent)
if err != nil {
log.Printf("[ERROR] Failed to write cache.go: %v", err)
return nil, errors.New("failed to write cache.go")
}
}
// Addons — delegated to the addon registry; new addon types need only a
// registration entry in registry.go, no changes here.
for addonType, addons := range request.Addons {
gen, ok := addonRegistry[addonType]
if !ok || len(addons) == 0 {
continue
}
if err := gen.Generate(folderName, addons, zipWriter); err != nil {
log.Printf("[ERROR] Failed to generate %s addon: %v", addonType, err)
return nil, fmt.Errorf("failed to generate %s addon: %w", addonType, err)
}
}

// 4. internal/service.go
serviceGoContent := "package internal\n\n// Business logic goes here\nfunc Service() string {\n return \"Service logic\"\n}\n"
serviceGoPath := fmt.Sprintf("%s/internal/service.go", folderName)
serviceGoFile, err := zipWriter.Create(serviceGoPath)
if err != nil {
log.Printf("[ERROR] Failed to create service.go in zip: %v", err)
return nil, errors.New("failed to create service.go in zip")
// internal/service.go
serviceContent := "package internal\n\n// Business logic goes here\nfunc Service() string {\n\treturn \"Service logic\"\n}\n"
if err := addToZip(zipWriter, fmt.Sprintf("%s/internal/service.go", folderName), []byte(serviceContent)); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}
_, err = serviceGoFile.Write([]byte(serviceGoContent))
if err != nil {
log.Printf("[ERROR] Failed to write service.go: %v", err)
return nil, errors.New("failed to write service.go")

// .gitignore
if err := addToZip(zipWriter, fmt.Sprintf("%s/.gitignore", folderName), GenerateGitignore()); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}

// check for docker support
// Dockerfile (optional)
if request.DockerSupport {
dockerfilePath := fmt.Sprintf("%s/Dockerfile", folderName)
content := GenerateDockerfile(request)
dockerfile, err := zipWriter.Create(dockerfilePath)
if err != nil {
log.Printf("[ERROR] Failed to create Dockerfile in zip: %v", err)
return nil, errors.New("failed to create Dockerfile in zip")
}
_, err = dockerfile.Write([]byte(content))
if err != nil {
log.Printf("[ERROR] Failed to write Dockerfile: %v", err)
return nil, errors.New("failed to write Dockerfile")
if err := addToZip(zipWriter, fmt.Sprintf("%s/Dockerfile", folderName), GenerateDockerfile(request)); err != nil {
log.Printf("[ERROR] %v", err)
return nil, err
}
}

err = zipWriter.Close()
if err != nil {
if err := zipWriter.Close(); err != nil {
log.Printf("[ERROR] Failed to close zip writer: %v", err)
return nil, errors.New("failed to finalize zip file")
return nil, fmt.Errorf("failed to finalize zip: %w", err)
}

return buf, nil
}

// myproject/
// ├── cmd/
// │ └── myproject/
// │ └── main.go
Loading
Loading