-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add Go build workflow and Makefile
- Loading branch information
1 parent
78cc846
commit 30a1915
Showing
11 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
name: Go | ||
|
||
env: | ||
GO_VERSION: '1.23' | ||
GO_LINT_VERSION: 'v1.60.3' | ||
|
||
on: | ||
push: | ||
branches: | ||
- develop | ||
- main | ||
|
||
pull_request: | ||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
go-version: ${{env.GO_VERSION}} | ||
- name: Build | ||
run: make build | ||
|
||
lint: | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
go-version: ${{env.GO_VERSION}} | ||
- name: golangci-lint | ||
uses: golangci/golangci-lint-action@v6 | ||
with: | ||
version: ${{env.GO_LINT_VERSION}} | ||
|
||
test: | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
go-version: ${{env.GO_VERSION}} | ||
- name: Test | ||
run: make test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
linters: | ||
disable-all: true | ||
enable: | ||
- bodyclose | ||
- errcheck | ||
- dogsled | ||
- errcheck | ||
- exhaustive | ||
- funlen | ||
- goconst | ||
- gocritic | ||
- gocyclo | ||
- gofmt | ||
- goimports | ||
- goprintffuncname | ||
- gosimple | ||
- govet | ||
- ineffassign | ||
- lll | ||
- maintidx | ||
- misspell | ||
- nakedret | ||
- nakedret | ||
- nestif | ||
- nilerr | ||
- noctx | ||
- nolintlint | ||
- revive | ||
- rowserrcheck | ||
- staticcheck | ||
- unused | ||
- typecheck | ||
- unconvert | ||
- unparam | ||
- unused | ||
- whitespace | ||
|
||
issues: | ||
exclude-rules: | ||
- path: _test\.go | ||
linters: | ||
- errcheck | ||
- noctx | ||
- govet | ||
- staticcheck | ||
- bodyclose | ||
- funlen |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
run: | ||
go run -race cmd/api.go | ||
|
||
build: | ||
go build -race -o bin/main cmd/api.go | ||
|
||
lint: | ||
golangci-lint run ./... | ||
|
||
test: | ||
go test -race -coverprofile=coverage.txt ./... | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log/slog" | ||
"os" | ||
|
||
"github.com/edmarfelipe/go-ci/internal/env" | ||
"github.com/edmarfelipe/go-ci/internal/httpserver" | ||
) | ||
|
||
func main() { | ||
if err := run(); err != nil { | ||
slog.Error("failed to start", "err", err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func run() error { | ||
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil))) | ||
|
||
cfg, err := env.Load() | ||
if err != nil { | ||
return fmt.Errorf("error loading configs: %w", err) | ||
} | ||
|
||
err = httpserver.New(cfg).Start() | ||
if err != nil { | ||
return fmt.Errorf("error starting the http server: %w", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/edmarfelipe/go-ci | ||
|
||
go 1.23.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package env | ||
|
||
import ( | ||
"os" | ||
) | ||
|
||
type Env struct { | ||
ServiceAddr string | ||
} | ||
|
||
// Load loads the environment variables from the system | ||
func Load() (*Env, error) { | ||
return &Env{ | ||
ServiceAddr: getEnv("SERVICE_PORT", ":8080"), | ||
}, nil | ||
} | ||
|
||
// getEnv returns the value of an environment variable, or a fallback value if it's not set. | ||
func getEnv(key string, fallback string) string { | ||
if value, ok := os.LookupEnv(key); ok { | ||
return value | ||
} | ||
return fallback | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package httpserver | ||
|
||
import ( | ||
"net/http" | ||
) | ||
|
||
type HealthResponse struct { | ||
Status string `json:"status"` | ||
} | ||
|
||
func HealthHandler(w http.ResponseWriter, _ *http.Request) { | ||
WriteJSON(w, http.StatusOK, HealthResponse{Status: "ok"}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package httpserver_test | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/edmarfelipe/go-ci/internal/httpserver" | ||
) | ||
|
||
func TestHealthHandler(t *testing.T) { | ||
t.Run("Should return a health response", func(t *testing.T) { | ||
srv := httptest.NewServer(http.HandlerFunc(httpserver.HealthHandler)) | ||
|
||
resp, err := http.Get(srv.URL) | ||
if err != nil { | ||
t.Fatalf("expected no error, got %v", err) | ||
} | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
t.Fatalf("expected status code %d, got %d", http.StatusOK, resp.StatusCode) | ||
} | ||
defer resp.Body.Close() | ||
|
||
var health httpserver.HealthResponse | ||
json.NewDecoder(resp.Body).Decode(&health) | ||
|
||
if health.Status != "ok" { | ||
t.Fatalf("expected status %s, got %s", "ok", health.Status) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package httpserver | ||
|
||
import ( | ||
"log/slog" | ||
"net/http" | ||
|
||
"github.com/edmarfelipe/go-ci/internal/env" | ||
) | ||
|
||
type HTTPServer struct { | ||
srv *http.Server | ||
} | ||
|
||
func New(cfg *env.Env) *HTTPServer { | ||
router := http.NewServeMux() | ||
router.HandleFunc("GET /health", HealthHandler) | ||
|
||
return &HTTPServer{ | ||
srv: &http.Server{ | ||
Addr: cfg.ServiceAddr, | ||
Handler: router, | ||
}, | ||
} | ||
} | ||
|
||
func (s *HTTPServer) Start() error { | ||
slog.Info("starting http server", "addr", s.srv.Addr) | ||
return s.srv.ListenAndServe() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package httpserver | ||
|
||
import ( | ||
"encoding/json" | ||
"log/slog" | ||
"net/http" | ||
) | ||
|
||
// ErrorResponse is a generic error response. | ||
type ErrorResponse struct { | ||
Error string `json:"error"` | ||
} | ||
|
||
// WriteBadRequest writes a bad request response. | ||
func WriteBadRequest(w http.ResponseWriter, err string) { | ||
WriteJSON(w, http.StatusBadRequest, ErrorResponse{Error: err}) | ||
} | ||
|
||
// WriteNotFound writes a not found response. | ||
func WriteNotFound(w http.ResponseWriter, err string) { | ||
WriteJSON(w, http.StatusNotFound, ErrorResponse{Error: err}) | ||
} | ||
|
||
// WriteUnauthorized writes an unauthorized response. | ||
func WriteUnauthorized(w http.ResponseWriter, err string) { | ||
WriteJSON(w, http.StatusUnauthorized, ErrorResponse{Error: err}) | ||
} | ||
|
||
// WriteInternalError logs the error and writes a generic error response. | ||
func WriteInternalError(w http.ResponseWriter, err error) { | ||
slog.Error("internal error", "err", err.Error()) | ||
WriteJSON(w, http.StatusInternalServerError, ErrorResponse{Error: err.Error()}) | ||
} | ||
|
||
// WriteJSON writes a JSON response. | ||
func WriteJSON(w http.ResponseWriter, code int, data any) { | ||
w.Header().Set("Content-Type", "application/json") | ||
w.WriteHeader(code) | ||
err := json.NewEncoder(w).Encode(data) | ||
if err != nil { | ||
http.Error(w, "failed to write response", http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
// DecodeJSON decodes a JSON request body. | ||
func DecodeJSON[T any](r *http.Request) (T, error) { | ||
var v T | ||
if err := json.NewDecoder(r.Body).Decode(&v); err != nil { | ||
return v, err | ||
} | ||
return v, nil | ||
} |