Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ea64bc2
Add my version info to README
LamaKhaledd Aug 13, 2025
170eb00
Add my version info to README
LamaKhaledd Aug 13, 2025
fd5a40e
Add failing CI workflow
LamaKhaledd Aug 14, 2025
36a8136
Update CI to print Go version instead of forcing failure
LamaKhaledd Aug 14, 2025
2d63203
Update CI to print Go version instead of forcing failure
LamaKhaledd Aug 14, 2025
237d89b
Add unit tests for GetAPIKey
LamaKhaledd Aug 14, 2025
abcce48
Update CI to run tests and break code for failure check
LamaKhaledd Aug 14, 2025
809f2da
Fix intentional break
LamaKhaledd Aug 14, 2025
eb229a7
Add code coverage to CI tests
LamaKhaledd Aug 14, 2025
d7e2c13
Add CI test badge to README
LamaKhaledd Aug 14, 2025
4496531
Add formatting CI job
LamaKhaledd Aug 14, 2025
311d2d7
Add unused function to test CI linting
LamaKhaledd Aug 14, 2025
b0c69f4
Add unused function to test CI linting
LamaKhaledd Aug 14, 2025
11d7232
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
b4c4d8b
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
16cf734
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
ecbb939
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
3a79af3
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
04183b8
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
4829727
Remove unused function to fix CI
LamaKhaledd Aug 14, 2025
1643da5
Add gosec security scan to CI
LamaKhaledd Aug 14, 2025
bb08f0f
Fix gosec security issues: add ReadHeaderTimeout and handle write errors
LamaKhaledd Aug 14, 2025
a13a7a6
Add CD workflow
LamaKhaledd Aug 16, 2025
1fc66d3
Integration with Google Cloud
LamaKhaledd Aug 16, 2025
2137811
Integration with Google Cloud
LamaKhaledd Aug 16, 2025
05df641
Update homepage title
LamaKhaledd Aug 16, 2025
eaa1043
Update h1 text to 'Welcome to Notely'
LamaKhaledd Aug 16, 2025
ff99fee
Adding Turso Database link to CD file
LamaKhaledd Aug 16, 2025
bee0f45
Add DATABASE_URL secret and automatic migrations
LamaKhaledd Aug 16, 2025
f6ac7ef
5alaaaassss menshaaaan Allah
LamaKhaledd Aug 16, 2025
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
67 changes: 67 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CD

on:
push:
branches:
- main

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest

env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'

- name: Build production binary
run: |
chmod +x scripts/buildprod.sh
./scripts/buildprod.sh

- name: Authenticate to GCP
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}

- name: Set up gcloud CLI
uses: google-github-actions/setup-gcloud@v2
with:
project_id: notely-469212
version: 'latest'

- name: Build and Push Docker image
run: |
gcloud builds submit \
--tag us-central1-docker.pkg.dev/notely-469212/notely-ar-repo/my-app:latest

- name: Run database migrations
run: |
curl -sSfL https://get.tur.so/install.sh | bash
export PATH="$HOME/.turso/bin:$PATH"

turso auth login --url "${{ secrets.DATABASE_URL }}" --headless
turso db shell notely-db --execute "
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
"

- name: Deploy to Cloud Run
run: |
gcloud run deploy notely \
--image us-central1-docker.pkg.dev/notely-469212/notely-ar-repo/my-app:latest \
--region us-central1 \
--allow-unauthenticated \
--project notely-469212 \
--max-instances=4
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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.23.0"

- name: Run tests
run: go test -cover ./...

- name: Install gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest

- name: Run gosec security scan
run: gosec ./...

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.23.0"

- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest

- name: Lint with Staticcheck
run: staticcheck ./...
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ FROM --platform=linux/amd64 debian:stable-slim

RUN apt-get update && apt-get install -y ca-certificates

ADD notely /usr/bin/notely
WORKDIR /app

COPY notely ./notely
COPY static ./static

ENTRYPOINT ["./notely"]

CMD ["notely"]
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ 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!


wewe's version of Boot.dev's Notely app.
عملت ميرج قبل ما اعمل تيست جد اني وردة


![CI Tests](https://github.com/lamakhaledd/learn-cicd-starter/actions/workflows/ci.yml/badge.svg)
38 changes: 38 additions & 0 deletions internal/auth/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package auth

import (
"net/http"
"testing"
)

func TestGetAPIKey_Valid(t *testing.T) {
headers := http.Header{}
headers.Set("Authorization", "ApiKey 12345")

apiKey, err := GetAPIKey(headers)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if apiKey != "12345" {
t.Errorf("expected apiKey '12345', got %s", apiKey)
}
}

func TestGetAPIKey_MissingHeader(t *testing.T) {
headers := http.Header{}

_, err := GetAPIKey(headers)
if err != ErrNoAuthHeaderIncluded {
t.Errorf("expected ErrNoAuthHeaderIncluded, got %v", err)
}
}

func TestGetAPIKey_InvalidFormat(t *testing.T) {
headers := http.Header{}
headers.Set("Authorization", "Bearer token123")

_, err := GetAPIKey(headers)
if err == nil || err.Error() != "malformed authorization header" {
t.Errorf("expected malformed authorization header error, got %v", err)
}
}
4 changes: 3 additions & 1 deletion json.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
8 changes: 6 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"net/http"
"os"
"time"

"github.com/go-chi/chi"
"github.com/go-chi/cors"
Expand All @@ -24,6 +25,7 @@ type apiConfig struct {
//go:embed static/*
var staticFiles embed.FS


func main() {
err := godotenv.Load(".env")
if err != nil {
Expand Down Expand Up @@ -89,10 +91,12 @@ func main() {

router.Mount("/v1", v1Router)
srv := &http.Server{
Addr: ":" + port,
Handler: router,
Addr: ":" + port,
Handler: router,
ReadHeaderTimeout: 5 * time.Second,
}


log.Printf("Serving on port: %s\n", port)
log.Fatal(srv.ListenAndServe())
}
4 changes: 2 additions & 2 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

<head>
<meta charset="UTF-8">
<title>Notely</title>
<title>Welcome to Notely</title>
</head>

<body class="section">
<h1>Notely</h1>
<h1>Welcome to Notely</h1>

<div id="userCreationContainer" class="section">
<input id="nameField" type="text" placeholder="Enter your name">
Expand Down
Binary file added test.tar
Binary file not shown.