From 69bcba6f8d477f81236257d4b23d23143069f65b Mon Sep 17 00:00:00 2001 From: Iwan Bony Date: Tue, 28 Oct 2025 18:42:33 +0100 Subject: [PATCH 01/32] Add my name to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c2bec0368b..df7228fe01 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,4 @@ go build -o notely && ./notely *This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`. You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course! +IVAN From ef3590a41593f26b207c1475bedb91a06fdab5e6 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 10:28:03 +0100 Subject: [PATCH 02/32] add ci.yml file --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..249cc5258a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: ci + +on: + pull_request: + branches: [main] + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.25.1" + + - name: Force Failure + run: (exit 1) From ddd00179c5a19d2361a328cf3df91573dc341b3c Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 10:35:59 +0100 Subject: [PATCH 03/32] change ci.yml file to print go version --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 249cc5258a..301df57d68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,5 +18,5 @@ jobs: with: go-version: "1.25.1" - - name: Force Failure - run: (exit 1) + - name: print go version + run: go version From cfa0a01f71880a54c07f60da7a9175905ea915f6 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 15:19:25 +0100 Subject: [PATCH 04/32] Replace go version with go test --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 301df57d68..7f54e41c77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,5 +18,5 @@ jobs: with: go-version: "1.25.1" - - name: print go version - run: go version + - name: Run tests + run: go test ./.. From 7b91ba15c060e66d7e0c10daf8df318d844fb433 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 16:20:27 +0100 Subject: [PATCH 05/32] Break test to verify CI catches failures --- internal/auth/auth_test.go | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 internal/auth/auth_test.go diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go new file mode 100644 index 0000000000..d41b1b4b28 --- /dev/null +++ b/internal/auth/auth_test.go @@ -0,0 +1,66 @@ +package auth + +import ( + "net/http" + "testing" + ) + +func TestGetAPIKey(t *testing.T) { + // Test case 1: Valid API key in header + t.Run("Valid API key", func(t *testing.T) { + headers := http.Header{} + headers.Set("Authorization", "ApiKey my-secret-key-123" ) + + apiKey, err := GetAPIKey(headers) + + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + expected := "wrong key" + if apiKey != expected { + t.Errorf("Expected %s, got %s", expected, apiKey) + } + }) + + // Test case 2: No Authorization header + t.Run("No Authorization header", func(t *testing.T) { + headers := http.Header{} + + _, err := GetAPIKey(headers ) + + if err == nil { + t.Fatal("Expected an error, got nil") + } + }) + + // Test case 3: Malformed Authorization header (missing "ApiKey") + t.Run("Malformed header - no ApiKey prefix", func(t *testing.T) { + headers := http.Header{} + headers.Set("Authorization", "Bearer my-token" ) + + _, err := GetAPIKey(headers) + + if err == nil { + t.Fatal("Expected an error, got nil") + } + }) + + // Test case 4: Malformed Authorization header (only "ApiKey", no key) + t.Run("Malformed header - no key value", func(t *testing.T) { + headers := http.Header{} + headers.Set("Authorization", "ApiKey" ) + + _, err := GetAPIKey(headers) + + if err == nil { + t.Fatal("Expected an error, got nil") + } + }) +} + + + + + + From d699bcecfa500168488eced2fa85ecec7032da85 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 16:29:35 +0100 Subject: [PATCH 06/32] Fix test - CI should pass now --- internal/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index d41b1b4b28..a61be9671e 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -17,7 +17,7 @@ func TestGetAPIKey(t *testing.T) { t.Fatalf("Expected no error, got %v", err) } - expected := "wrong key" + expected := "my-secret-key-123" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } From e9cee4122fe2240fc2808839f36b617d04affa5b Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 16:42:21 +0100 Subject: [PATCH 07/32] Break test to verify CI catches failures --- internal/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index a61be9671e..deb428a84f 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -17,7 +17,7 @@ func TestGetAPIKey(t *testing.T) { t.Fatalf("Expected no error, got %v", err) } - expected := "my-secret-key-123" + expected := "wrong-key" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } From d91474e93f46f4f0ca6399d62ea7fffb1073db4b Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 16:46:32 +0100 Subject: [PATCH 08/32] Fix test - CI should pass --- internal/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index deb428a84f..a61be9671e 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -17,7 +17,7 @@ func TestGetAPIKey(t *testing.T) { t.Fatalf("Expected no error, got %v", err) } - expected := "wrong-key" + expected := "my-secret-key-123" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } From 7de2d87fa0fd331b9f30629e13bbbfcfebcf9530 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 18:01:22 +0100 Subject: [PATCH 09/32] Fix test - should pass on CI --- internal/auth/auth_test.go | 40 ++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index a61be9671e..948b388a43 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -3,64 +3,58 @@ package auth import ( "net/http" "testing" - ) +) func TestGetAPIKey(t *testing.T) { // Test case 1: Valid API key in header t.Run("Valid API key", func(t *testing.T) { headers := http.Header{} - headers.Set("Authorization", "ApiKey my-secret-key-123" ) - + headers.Set("Authorization", "ApiKey my-secret-key-123") + apiKey, err := GetAPIKey(headers) - + if err != nil { t.Fatalf("Expected no error, got %v", err) } - + expected := "my-secret-key-123" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } }) - + // Test case 2: No Authorization header t.Run("No Authorization header", func(t *testing.T) { headers := http.Header{} - - _, err := GetAPIKey(headers ) - + + _, err := GetAPIKey(headers) + if err == nil { t.Fatal("Expected an error, got nil") } }) - + // Test case 3: Malformed Authorization header (missing "ApiKey") t.Run("Malformed header - no ApiKey prefix", func(t *testing.T) { headers := http.Header{} - headers.Set("Authorization", "Bearer my-token" ) - + headers.Set("Authorization", "Bearer my-token") + _, err := GetAPIKey(headers) - + if err == nil { t.Fatal("Expected an error, got nil") } }) - + // Test case 4: Malformed Authorization header (only "ApiKey", no key) t.Run("Malformed header - no key value", func(t *testing.T) { headers := http.Header{} - headers.Set("Authorization", "ApiKey" ) - + headers.Set("Authorization", "ApiKey") + _, err := GetAPIKey(headers) - + if err == nil { t.Fatal("Expected an error, got nil") } }) } - - - - - - From 12d7c1280f772fb8f9f56907c88e158023137bb6 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 18:31:40 +0100 Subject: [PATCH 10/32] --- test --- internal/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index 948b388a43..c897382ea0 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -17,7 +17,7 @@ func TestGetAPIKey(t *testing.T) { t.Fatalf("Expected no error, got %v", err) } - expected := "my-secret-key-123" + expected := "my-secret-key-" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } From 999d692918f5ea0f5b8d24faa6c1c408dc2c1a11 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 18:34:47 +0100 Subject: [PATCH 11/32] Fix test - should pass on CI --- internal/auth/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index c897382ea0..948b388a43 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -17,7 +17,7 @@ func TestGetAPIKey(t *testing.T) { t.Fatalf("Expected no error, got %v", err) } - expected := "my-secret-key-" + expected := "my-secret-key-123" if apiKey != expected { t.Errorf("Expected %s, got %s", expected, apiKey) } From d0a6193df5a3ae42aedeb91dae563abcf619770e Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 20:52:20 +0100 Subject: [PATCH 12/32] Update CI workflow --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f54e41c77..1895256cb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,3 +20,5 @@ jobs: - name: Run tests run: go test ./.. + + From d10797f0bdd483027a15e608635d6aeb8853203b Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 21:02:09 +0100 Subject: [PATCH 13/32] Fix CI workflow - correct checkout and go version --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1895256cb1..81ffb365b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,9 +16,8 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.25.1" + go-version: "1.22" - name: Run tests - run: go test ./.. - + run: go test ./... From 2d71716325146ac05a4a53f335979e3653a922ea Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 22:07:49 +0100 Subject: [PATCH 14/32] add code coverage to CI tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81ffb365b1..e0867175ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,5 +19,5 @@ jobs: go-version: "1.22" - name: Run tests - run: go test ./... + run: go test ./... --cover From 9a212362a4c755caa3cc17032b4766e75e02a676 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 22:28:38 +0100 Subject: [PATCH 15/32] Add CI badge to README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df7228fe01..99426dd032 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# learn-cicd-starter (Notely) +![CI](https://github.com/ivanbonifazi-cpu/learn-cicd-starter/actions/workflows/ci.yml/badge.svg ) + + # learn-cicd-starter (Notely) This repo contains the starter code for the "Notely" application for the "Learn CICD" course on [Boot.dev](https://boot.dev). From 39a81ec996fa9f95024d330161509e4fab2bdb11 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Thu, 30 Oct 2025 23:14:56 +0100 Subject: [PATCH 16/32] Fix badge syntax - remove extra space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99426dd032..a6a520b750 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![CI](https://github.com/ivanbonifazi-cpu/learn-cicd-starter/actions/workflows/ci.yml/badge.svg ) +![CI](https://github.com/ivanbonifazi-cpu/learn-cicd-starter/actions/workflows/ci.yml/badge.svg) # learn-cicd-starter (Notely) From 4a765e3028ee20deb5e4013a491e981cacc058b3 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 08:13:25 +0100 Subject: [PATCH 17/32] Add style check to CI workflow --- .github/workflows/ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0867175ea..79236cef65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,3 +21,18 @@ jobs: - name: Run tests run: go test ./... --cover + style: + name: Style + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" + + - name: Check formatting + run: test -z $(go fmt ./...) From 4ef2889e1832f0ad460cc4547cfc2819866399c1 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 08:17:48 +0100 Subject: [PATCH 18/32] Add style check to CI workflow --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79236cef65..d58f5f9650 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - name: Run tests run: go test ./... --cover - style: + style: name: Style runs-on: ubuntu-latest @@ -36,3 +36,4 @@ jobs: - name: Check formatting run: test -z $(go fmt ./...) + From ce3f39b97655c5ce5108a0049c92f94c85dac568 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 08:35:55 +0100 Subject: [PATCH 19/32] Trigger CI - code is formatted From 13cebb98e71a28381d5639b3b92e89df2c4a5f92 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 09:05:06 +0100 Subject: [PATCH 20/32] Fix YAML syntax in CI workflow --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d58f5f9650..365fe24fb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,4 +36,3 @@ jobs: - name: Check formatting run: test -z $(go fmt ./...) - From 97cf01dd6025b44ecd3938921f7093d62e387345 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 11:51:36 +0100 Subject: [PATCH 21/32] Add staticcheck to CI style job --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 365fe24fb1..1fbc445c4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,3 +36,10 @@ jobs: - name: Check formatting run: test -z $(go fmt ./...) + + - name: Print go Version + run: go version + + - name: Run staticcheck + run: staticcheck ./... + From 4c806c0e45beab3dd914ea899ca7d5b47fc5f9c9 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 11:55:20 +0100 Subject: [PATCH 22/32] Add unused function to test staticcheck --- main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.go b/main.go index 19d7366c5f..90479ba775 100644 --- a/main.go +++ b/main.go @@ -96,3 +96,8 @@ func main() { log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) } + +func unused() { + // this function does nothing +} + From fecc86ce8ca6c353fddd993eba96ce75f9339d67 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 12:03:16 +0100 Subject: [PATCH 23/32] Removed unused Function --- main.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/main.go b/main.go index 90479ba775..19d7366c5f 100644 --- a/main.go +++ b/main.go @@ -96,8 +96,3 @@ func main() { log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) } - -func unused() { - // this function does nothing -} - From 02c7aaadf3672720201ecd99e0841e8bbf4e5077 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 12:08:01 +0100 Subject: [PATCH 24/32] Removed unused Function --- main.go | 107 ++++++++------------------------------------------------ 1 file changed, 14 insertions(+), 93 deletions(-) diff --git a/main.go b/main.go index 19d7366c5f..70523d993c 100644 --- a/main.go +++ b/main.go @@ -1,98 +1,19 @@ -package main + style: + name: Style + runs-on: ubuntu-latest -import ( - "database/sql" - "embed" - "io" - "log" - "net/http" - "os" + steps: + - name: Check out code + uses: actions/checkout@v4 - "github.com/go-chi/chi" - "github.com/go-chi/cors" - "github.com/joho/godotenv" + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" - "github.com/bootdotdev/learn-cicd-starter/internal/database" + - name: Check formatting + run: test -z $(go fmt ./...) - _ "github.com/tursodatabase/libsql-client-go/libsql" -) + - name: Run staticcheck + run: staticcheck ./... -type apiConfig struct { - DB *database.Queries -} - -//go:embed static/* -var staticFiles embed.FS - -func main() { - err := godotenv.Load(".env") - if err != nil { - log.Printf("warning: assuming default configuration. .env unreadable: %v", err) - } - - port := os.Getenv("PORT") - if port == "" { - log.Fatal("PORT environment variable is not set") - } - - apiCfg := apiConfig{} - - // https://github.com/libsql/libsql-client-go/#open-a-connection-to-sqld - // libsql://[your-database].turso.io?authToken=[your-auth-token] - dbURL := os.Getenv("DATABASE_URL") - if dbURL == "" { - log.Println("DATABASE_URL environment variable is not set") - log.Println("Running without CRUD endpoints") - } else { - db, err := sql.Open("libsql", dbURL) - if err != nil { - log.Fatal(err) - } - dbQueries := database.New(db) - apiCfg.DB = dbQueries - log.Println("Connected to database!") - } - - router := chi.NewRouter() - - router.Use(cors.Handler(cors.Options{ - AllowedOrigins: []string{"https://*", "http://*"}, - AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, - AllowedHeaders: []string{"*"}, - ExposedHeaders: []string{"Link"}, - AllowCredentials: false, - MaxAge: 300, - })) - - router.Get("/", func(w http.ResponseWriter, r *http.Request) { - f, err := staticFiles.Open("static/index.html") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer f.Close() - if _, err := io.Copy(w, f); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - }) - - v1Router := chi.NewRouter() - - if apiCfg.DB != nil { - v1Router.Post("/users", apiCfg.handlerUsersCreate) - v1Router.Get("/users", apiCfg.middlewareAuth(apiCfg.handlerUsersGet)) - v1Router.Get("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesGet)) - v1Router.Post("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesCreate)) - } - - v1Router.Get("/healthz", handlerReadiness) - - router.Mount("/v1", v1Router) - srv := &http.Server{ - Addr: ":" + port, - Handler: router, - } - - log.Printf("Serving on port: %s\n", port) - log.Fatal(srv.ListenAndServe()) -} From 3285c6806f8de184a4e5f4e728d29c4f9e265182 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 12:12:15 +0100 Subject: [PATCH 25/32] Removed unused Function --- main.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/main.go b/main.go index 70523d993c..80aa62a7f8 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,26 @@ +name: ci + +on: + pull_request: + branches: [main] + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" + + - name: Run tests + run: go test ./... --cover + style: name: Style runs-on: ubuntu-latest From 2f68bc0669c0ba5c7aaf046370bf3e99f4571f40 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 14:03:51 +0100 Subject: [PATCH 26/32] Removed unused Function --- main.go | 118 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/main.go b/main.go index 80aa62a7f8..19d7366c5f 100644 --- a/main.go +++ b/main.go @@ -1,42 +1,98 @@ -name: ci +package main -on: - pull_request: - branches: [main] +import ( + "database/sql" + "embed" + "io" + "log" + "net/http" + "os" -jobs: - tests: - name: Tests - runs-on: ubuntu-latest + "github.com/go-chi/chi" + "github.com/go-chi/cors" + "github.com/joho/godotenv" - steps: - - name: Check out code - uses: actions/checkout@v4 + "github.com/bootdotdev/learn-cicd-starter/internal/database" - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.22" + _ "github.com/tursodatabase/libsql-client-go/libsql" +) - - name: Run tests - run: go test ./... --cover +type apiConfig struct { + DB *database.Queries +} - style: - name: Style - runs-on: ubuntu-latest +//go:embed static/* +var staticFiles embed.FS - steps: - - name: Check out code - uses: actions/checkout@v4 +func main() { + err := godotenv.Load(".env") + if err != nil { + log.Printf("warning: assuming default configuration. .env unreadable: %v", err) + } - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.22" + port := os.Getenv("PORT") + if port == "" { + log.Fatal("PORT environment variable is not set") + } - - name: Check formatting - run: test -z $(go fmt ./...) + apiCfg := apiConfig{} - - name: Run staticcheck - run: staticcheck ./... + // https://github.com/libsql/libsql-client-go/#open-a-connection-to-sqld + // libsql://[your-database].turso.io?authToken=[your-auth-token] + dbURL := os.Getenv("DATABASE_URL") + if dbURL == "" { + log.Println("DATABASE_URL environment variable is not set") + log.Println("Running without CRUD endpoints") + } else { + db, err := sql.Open("libsql", dbURL) + if err != nil { + log.Fatal(err) + } + dbQueries := database.New(db) + apiCfg.DB = dbQueries + log.Println("Connected to database!") + } + router := chi.NewRouter() + + router.Use(cors.Handler(cors.Options{ + AllowedOrigins: []string{"https://*", "http://*"}, + AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, + AllowedHeaders: []string{"*"}, + ExposedHeaders: []string{"Link"}, + AllowCredentials: false, + MaxAge: 300, + })) + + router.Get("/", func(w http.ResponseWriter, r *http.Request) { + f, err := staticFiles.Open("static/index.html") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer f.Close() + if _, err := io.Copy(w, f); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }) + + v1Router := chi.NewRouter() + + if apiCfg.DB != nil { + v1Router.Post("/users", apiCfg.handlerUsersCreate) + v1Router.Get("/users", apiCfg.middlewareAuth(apiCfg.handlerUsersGet)) + v1Router.Get("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesGet)) + v1Router.Post("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesCreate)) + } + + v1Router.Get("/healthz", handlerReadiness) + + router.Mount("/v1", v1Router) + srv := &http.Server{ + Addr: ":" + port, + Handler: router, + } + + log.Printf("Serving on port: %s\n", port) + log.Fatal(srv.ListenAndServe()) +} From 410a464dc86d408f1d0e5444a96e0cdb6f34b39f Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 14:11:54 +0100 Subject: [PATCH 27/32] Install staticcheck in CI workflow --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fbc445c4d..73196246ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,9 +36,9 @@ jobs: - name: Check formatting run: test -z $(go fmt ./...) - - - name: Print go Version - run: go version + + - name: Install staticcheck + run: go install honnef.co/go/tools/cmd/staticcheck@latest - name: Run staticcheck run: staticcheck ./... From ae321e40bd3a8010a9a96b6f4cdc26cbe87b828c Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 14:23:41 +0100 Subject: [PATCH 28/32] Add go sec install --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73196246ce..f882e9ffa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,3 +43,5 @@ jobs: - name: Run staticcheck run: staticcheck ./... + - name: Install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@latest From 8fb3ceda50b3a8dc519bda58237f5a1b8e6998c4 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Fri, 31 Oct 2025 15:46:04 +0100 Subject: [PATCH 29/32] Fix gosec security issues --- json.go | 4 +++- main.go | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/json.go b/json.go index 1e6e7985e1..b9f6642aa6 100644 --- a/json.go +++ b/json.go @@ -30,5 +30,7 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { return } w.WriteHeader(code) - w.Write(dat) + if _, err := w.Write(dat); err != nil { + log.Printf("Error writing response: %v", err) } + diff --git a/main.go b/main.go index 19d7366c5f..324fea2ecc 100644 --- a/main.go +++ b/main.go @@ -91,6 +91,7 @@ func main() { srv := &http.Server{ Addr: ":" + port, Handler: router, + ReadHeaderTimeout: 10 * time.Second, } log.Printf("Serving on port: %s\n", port) From 82a61ed3b9e043f9a89fb901dd0abe9508b2be76 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Mon, 3 Nov 2025 12:41:41 +0100 Subject: [PATCH 30/32] Fix missing closing brace in json.go --- json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json.go b/json.go index b9f6642aa6..0734bf62ba 100644 --- a/json.go +++ b/json.go @@ -32,5 +32,5 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { w.WriteHeader(code) if _, err := w.Write(dat); err != nil { log.Printf("Error writing response: %v", err) + } } - From 87afe25016c6c7db962c204263d4d556eb1054df Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Mon, 3 Nov 2025 12:51:15 +0100 Subject: [PATCH 31/32] Add time import to main.go --- main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 324fea2ecc..0930c3be6d 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,9 @@ package main -import ( + import ( "database/sql" "embed" + "time" "io" "log" "net/http" From 0d5e306eaade3bfcbfa617384a6f59a89b8e1307 Mon Sep 17 00:00:00 2001 From: ivan bonifazi Date: Mon, 3 Nov 2025 12:55:44 +0100 Subject: [PATCH 32/32] Format code with go fmt --- json.go | 6 +++--- main.go | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/json.go b/json.go index 0734bf62ba..6e505b3849 100644 --- a/json.go +++ b/json.go @@ -30,7 +30,7 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { return } w.WriteHeader(code) - if _, err := w.Write(dat); err != nil { - log.Printf("Error writing response: %v", err) - } + if _, err := w.Write(dat); err != nil { + log.Printf("Error writing response: %v", err) + } } diff --git a/main.go b/main.go index 0930c3be6d..72873fee93 100644 --- a/main.go +++ b/main.go @@ -1,13 +1,13 @@ package main - import ( +import ( "database/sql" "embed" - "time" "io" "log" "net/http" "os" + "time" "github.com/go-chi/chi" "github.com/go-chi/cors" @@ -90,9 +90,9 @@ func main() { router.Mount("/v1", v1Router) srv := &http.Server{ - Addr: ":" + port, - Handler: router, - ReadHeaderTimeout: 10 * time.Second, + Addr: ":" + port, + Handler: router, + ReadHeaderTimeout: 10 * time.Second, } log.Printf("Serving on port: %s\n", port)