Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
71db684
Update README with note on CSgyz's Notely app
CSgyz Apr 21, 2026
fd15c74
Add CI workflow for pull requests
CSgyz Apr 21, 2026
ec41d88
Change Force Failure step to exit with success
CSgyz Apr 21, 2026
d43fd38
Add test cases for GetAPIKey function
CSgyz Apr 22, 2026
ad98585
Change error message for malformed auth header
CSgyz Apr 22, 2026
807986a
Update CI workflow to run tests
CSgyz Apr 22, 2026
20a40b3
Improve error message for malformed auth header
CSgyz Apr 22, 2026
5fa4cdc
Update test command to include coverage
CSgyz Apr 22, 2026
798011a
Add CI badge to README
CSgyz Apr 22, 2026
18e057a
Fix formatting of error handling in handler_user.go
CSgyz Apr 22, 2026
b18de09
Remove extra newline in handlerReadiness function
CSgyz Apr 22, 2026
d6d07d6
Rename 'Force Failure' to 'Auth Function Test' and add style check
CSgyz Apr 22, 2026
2b5dd7c
Fix quotes in code style check command
CSgyz Apr 22, 2026
5501e5f
Remove unnecessary blank line in middleware_auth.go
CSgyz Apr 22, 2026
47aad04
check code format
CSgyz Apr 22, 2026
dbeb44f
fix code format function
CSgyz Apr 22, 2026
2c488d2
Add formatting output step to CI workflow
CSgyz Apr 22, 2026
3ddbf3b
Rename job from 'Tests' to 'Style'
CSgyz Apr 22, 2026
f6c0d44
Add unused function for future use
CSgyz Apr 22, 2026
6b1e968
Add staticcheck installation step in CI workflow
CSgyz Apr 22, 2026
28fe9aa
Install gosec in CI workflow
CSgyz Apr 22, 2026
61c62fa
Add gosec step to CI workflow
CSgyz Apr 22, 2026
83c2e75
Add CI/CD workflow for deployment on push to main
CSgyz Apr 22, 2026
2317fef
Change log message format for serving port
CSgyz Apr 22, 2026
80a8332
Add ReadHeaderTimeout to HTTP server
CSgyz Apr 22, 2026
6a55b4d
Handle error when writing response data
CSgyz Apr 22, 2026
a880b01
Remove unnecessary blank line in json.go
CSgyz Apr 22, 2026
1056bc0
Update log message for server start
CSgyz Apr 22, 2026
ca0d476
Rename job from 'Style' to 'Tests' in CI workflow
CSgyz Apr 22, 2026
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
19 changes: 19 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
on:
push:
branches: [main]

jobs:
deploy:
name: Deploy
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.26.0"
- name: Build
run: ./scripts/buildprod.sh
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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.26.0"

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

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

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

- name: Auth Fuction Test
run: go test -cover ./...

- name: Show formatting output
run: go fmt ./...

- name: check code style
run: test -z "$(go fmt ./...)"
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
![alt text goes here](https://github.com/CSgyz/Boot.dev.CICD.learning/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).
Expand All @@ -21,3 +22,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!
CSgyz's version of Boot.dev's Notely app.
85 changes: 85 additions & 0 deletions internal/auth/get_api_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package auth

import (
"errors"
"net/http"
"testing"
)

func TestGetAPIKey(t *testing.T) {
tests := []struct {
name string
headers http.Header
wantKey string
wantErr bool
wantErrIs error
wantErrMsg string
}{
// 用例 1:缺失 Authorization 头
{
name: "缺失 Authorization 头",
headers: http.Header{},
wantKey: "",
wantErr: true,
wantErrIs: ErrNoAuthHeaderIncluded,
},
// 用例 2A:前缀错误
{
name: "前缀错误 Bearer 而非 ApiKey",
headers: http.Header{"Authorization": []string{"Bearer 12345"}},
wantKey: "",
wantErr: true,
wantErrMsg: "malformed authorization header",
},
// 用例 2B:只有前缀无 Token
{
name: "只有前缀无 Token",
headers: http.Header{"Authorization": []string{"ApiKey"}},
wantKey: "",
wantErr: true,
wantErrMsg: "malformed authorization header",
},
// 用例 2C:随机内容
{
name: "内容完全随机",
headers: http.Header{"Authorization": []string{"randomstuff"}},
wantKey: "",
wantErr: true,
wantErrMsg: "malformed authorization header",
},
// 用例 3:成功路径
{
name: "格式正确应返回 Key",
headers: http.Header{"Authorization": []string{"ApiKey 12345-abcde"}},
wantKey: "12345-abcde",
wantErr: false,
},
}
// 遍历所有用例
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotKey, err := GetAPIKey(tt.headers)

// 断言 key
if gotKey != tt.wantKey {
t.Errorf("key = %q, want %q", gotKey, tt.wantKey)
}

// 断言错误存在性
if (err != nil) != tt.wantErr {
t.Errorf("error = %v, wantErr = %v", err, tt.wantErr)
return
}

// 断言哨定错误(errors.Is)
if tt.wantErrIs != nil && !errors.Is(err, tt.wantErrIs) {
t.Errorf("error = %v, want errors.Is match %v", err, tt.wantErrIs)
}

// 断言错误消息内容
if tt.wantErrMsg != "" && err != nil && err.Error() != tt.wantErrMsg {
t.Errorf("error msg = %q, want %q", err.Error(), tt.wantErrMsg)
}
})
}
}
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)
_, err = w.Write(dat)
if err != nil {
log.Printf("Critical error writing response: %s", err)
}
8 changes: 7 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,14 @@ func main() {
srv := &http.Server{
Addr: ":" + port,
Handler: router,
ReadHeaderTimeout: time.Second * 5,
}

log.Printf("Serving on port: %s\n", port)
log.Println("Serving server")
log.Fatal(srv.ListenAndServe())
}

func unused() {
// this function does nothing
// and is called nowhere
}
3 changes: 1 addition & 2 deletions middleware_auth.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package main

import (
"net/http"

"github.com/bootdotdev/learn-cicd-starter/internal/auth"
"github.com/bootdotdev/learn-cicd-starter/internal/database"
"net/http"
)

type authedHandler func(http.ResponseWriter, *http.Request, database.User)
Expand Down
5 changes: 5 additions & 0 deletions notely.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
nohup: ignoring input
2026/04/21 17:54:50 warning: assuming default configuration. .env unreadable: open .env: no such file or directory
2026/04/21 17:54:50 DATABASE_URL environment variable is not set
2026/04/21 17:54:50 Running without CRUD endpoints
2026/04/21 17:54:50 Serving on port: 8080