DodoApp: Support postgresql config

Change-Id: I491553c709385b99d0bc1326dd967bd73c4fec6a
diff --git a/charts/app-runner/templates/install.yaml b/charts/app-runner/templates/install.yaml
index f89cc79..1e22086 100644
--- a/charts/app-runner/templates/install.yaml
+++ b/charts/app-runner/templates/install.yaml
@@ -51,6 +51,8 @@
 metadata:
   name: app-app
   namespace: {{ .Release.Namespace }}
+  annotations:
+    dodo.cloud/config-checksum: {{ sha256sum .Values.runCfg }}
 spec:
   selector:
     matchLabels:
@@ -60,6 +62,8 @@
     metadata:
       labels:
         app: app-app
+      annotations:
+        dodo.cloud/config-checksum: {{ sha256sum .Values.runCfg }}
     spec:
       runtimeClassName: {{ .Values.runtimeClassName }}
       volumes:
diff --git a/core/installer/app_configs/app_base.cue b/core/installer/app_configs/app_base.cue
index 9860c6c..4954bef 100644
--- a/core/installer/app_configs/app_base.cue
+++ b/core/installer/app_configs/app_base.cue
@@ -118,6 +118,11 @@
             "\(name)": #Image & image
         }
     }
+    for _, value in _postgresql {
+        for name, image in value.out.images {
+            "\(name)": #Image & image
+        }
+    }
 }
 
 charts: {}
@@ -134,6 +139,13 @@
             }
         }
     }
+    for _, value in _postgresql {
+        for name, chart in value.out.charts {
+            "\(name)": #Chart & chart & {
+                name: name
+            }
+        }
+    }
 }
 charts: {
 	volume: {
@@ -144,6 +156,104 @@
 	}
 }
 
+#PostgreSQL: {
+	name: string
+	version: "15.3"
+	initSQL: string | *""
+	size: string | *"1Gi"
+
+	_size: size
+	_volumeClaimName: "postgresql"
+
+	out: {
+		images: {
+			postgres: #Image & {
+				repository: "library"
+				name: "postgres"
+				tag: version
+				pullPolicy: "IfNotPresent"
+			}
+		}
+		charts: {
+			volume: #Chart & {
+				kind: "GitRepository"
+				address: "https://code.v1.dodo.cloud/helm-charts"
+				branch: "main"
+				path: "charts/volumes"
+			}
+			postgres: #Chart & {
+				kind: "GitRepository"
+				address: "https://code.v1.dodo.cloud/helm-charts"
+				branch: "main"
+				path: "charts/postgresql"
+			}
+		}
+		charts: {
+			for key, value in charts {
+				"\(key)": #Chart & value & {
+					name: key
+				}
+			}
+		}
+		helm: {
+			"volume-name": {
+				chart: charts.volume
+				values: {
+					name: _volumeClaimName
+					size: _size
+				}
+			}
+			postgres: {
+				chart: charts.postgres
+				values: {
+					fullnameOverride: "postgres"
+					image: {
+						registry: images.postgres.registry
+						repository: images.postgres.imageName
+						tag: images.postgres.tag
+						pullPolicy: images.postgres.pullPolicy
+					}
+					auth: {
+						username: "postgres"
+						password: "postgres"
+						database: "postgres"
+					}
+					service: {
+						type: "ClusterIP"
+						port: 5432
+					}
+					primary: {
+						persistence: existingClaim: _volumeClaimName
+						if initSQL != "" {
+							initdb: scripts: "init.sql": initSQL
+						}
+						securityContext: {
+							enabled: true
+							fsGroup: 0
+						}
+						containerSecurityContext: {
+							enabled: true
+							runAsUser: 0
+						}
+					}
+					volumePermissions: securityContext: runAsUser: 0
+				}
+			}
+		}
+	}
+}
+
+_ingressValidate: {}
+
+postgresql: {}
+_postgresql: {
+	for key, value in postgresql {
+		"\(key)": #PostgreSQL & value & {
+			name: key
+		}
+	}
+}
+
 localCharts: {
 	for key, _ in charts {
 		"\(key)": {
@@ -184,6 +294,13 @@
 			}
 		}
 	}
+	for key, value in _postgresql {
+		for post, postValue in value.out.helm {
+			"\(key)-\(post)": #Helm & postValue & {
+				name: "\(key)-\(post)"
+			}
+		}
+	}
 }
 
 #HelmRelease: {
diff --git a/core/installer/app_configs/app_global_env.cue b/core/installer/app_configs/app_global_env.cue
index 26e8a99..c53df4a 100644
--- a/core/installer/app_configs/app_global_env.cue
+++ b/core/installer/app_configs/app_global_env.cue
@@ -128,7 +128,6 @@
 }
 
 ingress: {}
-
 _ingressValidate: {
 	for key, value in ingress {
 		"\(key)": #Ingress & value
diff --git a/core/installer/app_configs/app_global_infra.cue b/core/installer/app_configs/app_global_infra.cue
index 937d490..b3069d0 100644
--- a/core/installer/app_configs/app_global_infra.cue
+++ b/core/installer/app_configs/app_global_infra.cue
@@ -19,7 +19,3 @@
 }
 
 networks: #Networks
-
-ingress: {}
-_ingressValidate: {}
-
diff --git a/core/installer/app_configs/dodo_app.cue b/core/installer/app_configs/dodo_app.cue
index 2a605e0..8a67645 100644
--- a/core/installer/app_configs/dodo_app.cue
+++ b/core/installer/app_configs/dodo_app.cue
@@ -24,6 +24,10 @@
 	...
 }
 
+#PostgreSQLs: {
+	...
+}
+
 app: {
 	volumes: {
 		for key, value in volumes {
@@ -32,6 +36,13 @@
 			}
 		}
 	}
+	postgresql: {
+		for key, value in postgresql {
+			"\(key)": #PostgreSQL & value & {
+				name: key
+			}
+		}
+	}
 }
 
 #Command: {
@@ -50,6 +61,7 @@
 	run: string | *"main.go"
 	ingress: #AppIngress
 	volumes: #Volumes
+	postgresql: #PostgreSQLs
 	port: int | *8080
 	rootDir: _appDir
 
@@ -66,6 +78,18 @@
 			for k, v in volumes {
 				"DODO_VOLUME_\(strings.ToUpper(k))=/dodo-volume/\(v.name)"
 			}
+			for k, v in postgresql {
+				"DODO_POSTGRESQL_\(strings.ToUpper(k))_ADDRESS=\(v.name).\(release.namespace).svc.cluster.local"
+			}
+			for k, v in postgresql {
+				"DODO_POSTGRESQL_\(strings.ToUpper(k))_USERNAME=postgres"
+			}
+			for k, v in postgresql {
+				"DODO_POSTGRESQL_\(strings.ToUpper(k))_PASSWORD=postgres"
+			}
+			for k, v in postgresql {
+				"DODO_POSTGRESQL_\(strings.ToUpper(k))_DATABASE=postgres"
+			}
 	    ]
 	}]
 }
@@ -88,6 +112,7 @@
 	type: _hugoLatest
 	ingress: #AppIngress
 	volumes: {}
+	postgresql: {}
 	port: int | *8080
 	rootDir: _appDir
 
@@ -115,6 +140,7 @@
 	type: "php:8.2-apache"
 	ingress: #AppIngress
 	volumes: {}
+	postgresql: {}
 	port: int | *80
 	rootDir: "/var/www/html"
 
@@ -168,6 +194,7 @@
 }
 
 volumes: app.volumes
+postgresql: app.postgresql
 
 helm: {
 	app: {
diff --git a/core/installer/app_configs/testapp.cue b/core/installer/app_configs/testapp.cue
index 8201ff6..7ab6829 100644
--- a/core/installer/app_configs/testapp.cue
+++ b/core/installer/app_configs/testapp.cue
@@ -6,7 +6,16 @@
 		subdomain: "testapp"
 		auth: enabled: false
 	}
-	volumes: data: size: "1Gi"
+	volumes: {
+		data: {
+			size: "1Gi"
+		}
+	}
+	postgresql: {
+		foo: {
+			size: "2Gi"
+		}
+	}
 }
 
 // do create app --type=go[1.22.0] [--run-cmd=(*default main.go)]
diff --git a/core/installer/app_test.go b/core/installer/app_test.go
index 53962fe..bf0ceac 100644
--- a/core/installer/app_test.go
+++ b/core/installer/app_test.go
@@ -5,6 +5,8 @@
 	"fmt"
 	"net"
 	"testing"
+
+	"cuelang.org/go/cue/errors"
 )
 
 var (
@@ -341,8 +343,12 @@
 func TestPCloudApp(t *testing.T) {
 	app, err := NewDodoApp(testAppCue)
 	if err != nil {
+		for _, e := range errors.Errors(err) {
+			t.Log(e)
+		}
 		t.Fatal(err)
 	}
+
 	release := Release{
 		Namespace:     "foo",
 		AppInstanceId: "foo-bar",
diff --git a/core/installer/welcome/app-tmpl/golang-1.22.0/app.cue.gotmpl b/core/installer/welcome/app-tmpl/golang-1.22.0/app.cue.gotmpl
deleted file mode 100755
index 8cec919..0000000
--- a/core/installer/welcome/app-tmpl/golang-1.22.0/app.cue.gotmpl
+++ /dev/null
@@ -1,9 +0,0 @@
-app: {
-	type: "golang:1.22.0"
-	run: "main.go"
-	ingress: {
-		network: "{{ .Network.Name }}"
-		subdomain: "{{ .Subdomain }}"
-		auth: enabled: false
-	}
-}
diff --git a/core/installer/welcome/app-tmpl/golang-1.22.0/go.mod.gotmpl b/core/installer/welcome/app-tmpl/golang-1.22.0/go.mod.gotmpl
deleted file mode 100755
index d526dcd..0000000
--- a/core/installer/welcome/app-tmpl/golang-1.22.0/go.mod.gotmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-module dodo.app
-
-go 1.22.0
\ No newline at end of file
diff --git a/core/installer/welcome/app-tmpl/golang-1.22.0/main.go b/core/installer/welcome/app-tmpl/golang-1.22.0/main.go
deleted file mode 100755
index 28c1368..0000000
--- a/core/installer/welcome/app-tmpl/golang-1.22.0/main.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package main
-
-import (
-	"flag"
-	"fmt"
-	"log"
-	"net/http"
-)
-
-var port = flag.Int("port", 8080, "Port to listen on")
-
-func handler(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintln(w, "Hello from Dodo App!")
-}
-
-func main() {
-	flag.Parse()
-	http.HandleFunc("/", handler)
-	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
-}
diff --git a/core/installer/welcome/app_tmpl_test.go b/core/installer/welcome/app_tmpl_test.go
index ddd142c..daaf4c8 100644
--- a/core/installer/welcome/app_tmpl_test.go
+++ b/core/installer/welcome/app_tmpl_test.go
@@ -44,25 +44,6 @@
 	}
 }
 
-func TestAppTmplGolang1220(t *testing.T) {
-	d, err := fs.Sub(appTmpl, "app-tmpl")
-	if err != nil {
-		t.Fatal(err)
-	}
-	store, err := NewAppTmplStoreFS(d)
-	if err != nil {
-		t.Fatal(err)
-	}
-	a, err := store.Find("golang-1.22.0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	out := soft.NewBillyRepoFS(memfs.New())
-	if err := a.Render(network, "testapp", out); err != nil {
-		t.Fatal(err)
-	}
-}
-
 func TestAppTmplHugoLatest(t *testing.T) {
 	d, err := fs.Sub(appTmpl, "app-tmpl")
 	if err != nil {
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index 7153f20..7c35d69 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -509,6 +509,7 @@
 			return
 		}
 		if err := s.updateDodoApp(instanceAppStatus, req.Repository.Name, s.appConfigs[req.Repository.Name].Namespace, networks); err != nil {
+			fmt.Printf("Error: %s\n", err.Error())
 			if err := s.st.CreateCommit(req.Repository.Name, req.After, commitMsg, err.Error()); err != nil {
 				fmt.Printf("Error: %s\n", err.Error())
 			}