diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 000000000..a651da77b
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,61 @@
+name: CI/CD
+on:
+ push:
+ branches: [main]
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ test-frontend:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-go@v5
+ with:
+ go-version-file: frontend/go.mod
+
+ - name: Run frontend tests
+ working-directory: frontend
+ run: go test ./... -v
+
+ test-backend:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-go@v5
+ with:
+ go-version-file: backend/go.mod
+
+ - name: Run backend tests
+ working-directory: backend
+ run: go test ./... -v
+
+ build-and-deploy:
+ runs-on: ubuntu-latest
+ needs: [test-frontend, test-backend]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build and push Backend
+ uses: docker/build-push-action@v5
+ with:
+ context: ./backend
+ push: true
+ tags: ghcr.io/${{ github.repository_owner }}/simple-fortune-backend:latest
+
+ - name: Build and push Frontend
+ uses: docker/build-push-action@v5
+ with:
+ context: ./frontend
+ push: true
+ tags: ghcr.io/${{ github.repository_owner }}/simple-fortune-frontend:latest
+
+ - name: Deploy
+ run: |
+ docker pull ghcr.io/${{ github.repository_owner }}/simple-fortune-backend:latest
+ docker pull ghcr.io/${{ github.repository_owner }}/simple-fortune-frontend:latest
+ echo "Deployed from GHCR"
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..13566b81b
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..639900d13
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..b16efce0e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/simple-fortune-cookie.iml b/.idea/simple-fortune-cookie.iml
new file mode 100644
index 000000000..25ed3f6e7
--- /dev/null
+++ b/.idea/simple-fortune-cookie.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/Dockerfile b/backend/Dockerfile
new file mode 100644
index 000000000..baf83374f
--- /dev/null
+++ b/backend/Dockerfile
@@ -0,0 +1,7 @@
+FROM golang:1.22
+WORKDIR /app
+COPY . .
+RUN go mod download
+RUN go build -o main .
+EXPOSE 9000
+CMD ["./main"]
\ No newline at end of file
diff --git a/backend/backend.exe b/backend/backend.exe
new file mode 100644
index 000000000..f79dff97f
Binary files /dev/null and b/backend/backend.exe differ
diff --git a/backend/main.go b/backend/main.go
index 650ef3963..4d140fa61 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -178,5 +178,5 @@ func main() {
mux.Handle("/fortunes/", fortuneH)
err := http.ListenAndServe(":9000", mux)
- fmt.Println("%v", err)
+ fmt.Printf("Result: %v\n", err)
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000..f756fe055
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+version: '3.8'
+
+services:
+ backend:
+ build:
+ context: ./backend
+ ports:
+ - "9000:9000"
+
+ frontend:
+ build:
+ context: ./frontend
+ ports:
+ - "8080:8080"
+ environment:
+ BACKEND_DNS: backend
+ BACKEND_PORT: 9000
\ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
new file mode 100644
index 000000000..4c397b7e9
--- /dev/null
+++ b/frontend/Dockerfile
@@ -0,0 +1,7 @@
+FROM golang:1.22
+WORKDIR /app
+COPY . .
+RUN go mod download
+RUN go build -o main .
+EXPOSE 8080
+CMD ["./main"]
\ No newline at end of file
diff --git a/frontend/frontend.exe b/frontend/frontend.exe
new file mode 100644
index 000000000..61543eb82
Binary files /dev/null and b/frontend/frontend.exe differ
diff --git a/frontend/main.go b/frontend/main.go
index bede472b4..3a85c474b 100644
--- a/frontend/main.go
+++ b/frontend/main.go
@@ -1,19 +1,19 @@
package main
import (
- "io"
- "fmt"
- "encoding/json"
- "html/template"
- "net/http"
- "log"
- "time"
- "bytes"
- "math/rand"
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "io"
+ "log"
+ "math/rand"
+ "net/http"
+ "time"
)
-var BACKEND_DNS=getEnv("BACKEND_DNS", "localhost")
-var BACKEND_PORT=getEnv("BACKEND_PORT", "9000")
+var BACKEND_DNS = getEnv("BACKEND_DNS", "localhost")
+var BACKEND_PORT = getEnv("BACKEND_PORT", "9000")
type fortune struct {
ID string `json:"id" redis:"id"`
@@ -21,85 +21,85 @@ type fortune struct {
}
type newFortune struct {
- Message string `json:"message"`
+ Message string `json:"message"`
}
// use a custom client, because we don't do blocking operations wihout timeouts
var myClient = &http.Client{Timeout: 10 * time.Second}
func HealthzHandler(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusOK)
- io.WriteString(w, "healthy")
+ w.WriteHeader(http.StatusOK)
+ io.WriteString(w, "healthy")
}
func main() {
- http.HandleFunc("/healthz", HealthzHandler)
+ http.HandleFunc("/healthz", HealthzHandler)
- http.HandleFunc("/api/random", func (w http.ResponseWriter, r *http.Request) {
- resp, err := myClient.Get(fmt.Sprintf("http://%s:%s/fortunes/random", BACKEND_DNS, BACKEND_PORT))
- if err != nil {
- log.Fatalln(err)
- fmt.Fprint(w, err)
- return
- }
+ http.HandleFunc("/api/random", func(w http.ResponseWriter, r *http.Request) {
+ resp, err := myClient.Get(fmt.Sprintf("http://%s:%s/fortunes/random", BACKEND_DNS, BACKEND_PORT))
+ if err != nil {
+ log.Fatalln(err)
+ fmt.Fprint(w, err)
+ return
+ }
- f := new(fortune)
- json.NewDecoder(resp.Body).Decode(f)
+ f := new(fortune)
+ json.NewDecoder(resp.Body).Decode(f)
- fmt.Fprint(w, f.Message)
- return
- })
+ fmt.Fprint(w, f.Message)
+ return
+ })
- http.HandleFunc("/api/all", func (w http.ResponseWriter, r *http.Request) {
- resp, err := myClient.Get(fmt.Sprintf("http://%s:%s/fortunes", BACKEND_DNS, BACKEND_PORT))
- if err != nil {
- log.Fatalln(err)
- fmt.Fprint(w, err)
- return
- }
+ http.HandleFunc("/api/all", func(w http.ResponseWriter, r *http.Request) {
+ resp, err := myClient.Get(fmt.Sprintf("http://%s:%s/fortunes", BACKEND_DNS, BACKEND_PORT))
+ if err != nil {
+ log.Fatalln(err)
+ fmt.Fprint(w, err)
+ return
+ }
- fortunes := new([]fortune)
- json.NewDecoder(resp.Body).Decode(fortunes)
+ fortunes := new([]fortune)
+ json.NewDecoder(resp.Body).Decode(fortunes)
- tmpl, err := template.ParseFiles("./templates/fortunes.html")
+ tmpl, err := template.ParseFiles("./templates/fortunes.html")
- if err != nil {
- log.Fatalln(err)
- fmt.Fprint(w, err)
- return
- }
+ if err != nil {
+ log.Fatalln(err)
+ fmt.Fprint(w, err)
+ return
+ }
- tmpl.Execute(w, fortunes)
- return
- })
+ tmpl.Execute(w, fortunes)
+ return
+ })
- http.HandleFunc("/api/add", func (w http.ResponseWriter, r *http.Request) {
+ http.HandleFunc("/api/add", func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "POST" {
- http.Error(w, "Use POST", http.StatusMethodNotAllowed)
- return
- }
+ if r.Method != "POST" {
+ http.Error(w, "Use POST", http.StatusMethodNotAllowed)
+ return
+ }
- f := new(newFortune)
- json.NewDecoder(r.Body).Decode(f)
+ f := new(newFortune)
+ json.NewDecoder(r.Body).Decode(f)
- var postUrl = fmt.Sprintf("http://%s:%s/fortunes", BACKEND_DNS, BACKEND_PORT)
- var jsonStr = []byte(fmt.Sprintf(`{"id": "%d", "message": "%s"}`, rand.Intn(10000), f.Message))
+ var postUrl = fmt.Sprintf("http://%s:%s/fortunes", BACKEND_DNS, BACKEND_PORT)
+ var jsonStr = []byte(fmt.Sprintf(`{"id": "%d", "message": "%s"}`, rand.Intn(10000), f.Message))
- _, err := myClient.Post(postUrl, "application/json", bytes.NewBuffer(jsonStr))
- if err != nil {
- log.Fatalln(err)
- fmt.Fprint(w, err)
- return
- }
+ _, err := myClient.Post(postUrl, "application/json", bytes.NewBuffer(jsonStr))
+ if err != nil {
+ log.Fatalln(err)
+ fmt.Fprint(w, err)
+ return
+ }
- fmt.Fprint(w, "Cookie added!")
+ fmt.Fprint(w, "Cookie added!") // comment
- return
- })
+ return
+ })
- http.Handle("/", http.FileServer(http.Dir("./static")))
- err := http.ListenAndServe(":8080", nil)
- fmt.Println("%v", err)
+ http.Handle("/", http.FileServer(http.Dir("./static")))
+ err := http.ListenAndServe(":8080", nil)
+ fmt.Printf("Result: %v\n", err)
}