Skip to content

Commit cf26065

Browse files
authored
Merge branch 'develop' into dependabot/go_modules/develop/golang.org/x/net-0.51.0
2 parents 6ceca10 + fcca4f4 commit cf26065

19 files changed

Lines changed: 495 additions & 105 deletions

File tree

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
- uses: actions/setup-go@v5
1818
with:
1919
go-version: 1.25.5
20+
- run: npm install -g npm@latest
2021
- uses: ./.github/actions/build-release-notes
2122
- uses: actions/setup-node@v4
2223
with:
@@ -144,4 +145,5 @@ jobs:
144145
- name: Publish
145146
run: task publish-npm-package VERSION=${GITHUB_REF##*/v}
146147
env:
147-
CGO_ENABLED: 0
148+
CGO_ENABLED: 0
149+
NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ tasks:
4747
dir: npm
4848
cmds:
4949
- npm version {{.VERSION}}
50-
- npm publish
50+
- npm publish --provenance
5151
npm-build-windows:
5252
cmds:
5353
- go build -o ./npm/dist/mokapi-windows-amd64/mokapi.exe -ldflags="-X mokapi/version.BuildVersion={{.VERSION}}" ./cmd/mokapi

acceptance/cmd_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"mokapi/config/static"
1010
"mokapi/engine"
1111
"mokapi/feature"
12+
"mokapi/health"
1213
"mokapi/providers/asyncapi3"
1314
"mokapi/providers/directory"
1415
mail2 "mokapi/providers/mail"
@@ -63,14 +64,29 @@ func Start(cfg *static.Config) (*Cmd, error) {
6364
app.UpdateConfig(e)
6465
})
6566

67+
apiHandler := api.New(app, cfg.Api)
6668
if u, err := api.BuildUrl(cfg.Api); err == nil {
67-
err = http.AddInternalService("api", u, api.New(app, cfg.Api))
69+
err = http.AddInternalService("api", u, apiHandler)
6870
if err != nil {
6971
return nil, err
7072
}
7173
} else {
7274
return nil, err
7375
}
76+
if cfg.Health.Enabled {
77+
if u, err := health.BuildUrl(cfg.Health); err == nil {
78+
if cfg.Api.Port == cfg.Health.Port {
79+
apiHandler.RegisterHealthHandler(u.Path, health.New(cfg.Health))
80+
} else {
81+
err = http.AddInternalService("health", u, health.New(cfg.Health))
82+
if err != nil {
83+
return nil, err
84+
}
85+
}
86+
} else {
87+
return nil, err
88+
}
89+
}
7490

7591
pool := safe.NewPool(context.Background())
7692
s := server.NewServer(pool, app, watcher, kafka, http, mailManager, ldap, scriptEngine)

acceptance/petstore_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type PetStoreSuite struct{ BaseSuite }
2424
func (suite *PetStoreSuite) SetupSuite() {
2525
cfg := static.NewConfig()
2626
cfg.Api.Port = try.GetFreePort()
27+
cfg.Health.Port = cfg.Api.Port
2728
cfg.Providers.File.Directories = []static.FileConfig{{Path: "./petstore"}}
2829
cfg.Api.Search.Enabled = true
2930
suite.initCmd(cfg)
@@ -392,3 +393,10 @@ func (suite *PetStoreSuite) TestSearch_Paging() {
392393
}),
393394
)
394395
}
396+
397+
func (suite *PetStoreSuite) TestHealth() {
398+
try.GetRequest(suite.T(), fmt.Sprintf("http://127.0.0.1:%v/health", suite.cfg.Api.Port), nil,
399+
try.HasStatusCode(http.StatusOK),
400+
try.HasBody(`{"status":"healthy"}`),
401+
)
402+
}

api/handler.go

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ import (
1919
log "github.com/sirupsen/logrus"
2020
)
2121

22+
type Handler interface {
23+
http.Handler
24+
RegisterHealthHandler(path string, h http.Handler)
25+
}
26+
2227
type handler struct {
23-
config static.Api
24-
path string
25-
base string
26-
app *runtime.App
27-
fileServer http.Handler
28-
index string
28+
config static.Api
29+
path string
30+
base string
31+
app *runtime.App
32+
fileServer http.Handler
33+
index string
34+
healthPath string
35+
healthHandler http.Handler
2936
}
3037

3138
type info struct {
@@ -67,7 +74,7 @@ type apiError struct {
6774
Message string `json:"message"`
6875
}
6976

70-
func New(app *runtime.App, config static.Api) http.Handler {
77+
func New(app *runtime.App, config static.Api) Handler {
7178
h := &handler{
7279
config: config,
7380
path: config.Path,
@@ -99,6 +106,11 @@ func BuildUrl(cfg static.Api) (*url.URL, error) {
99106
return url.Parse(s)
100107
}
101108

109+
func (h *handler) RegisterHealthHandler(path string, handler http.Handler) {
110+
h.healthPath = path
111+
h.healthHandler = handler
112+
}
113+
102114
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
103115
if r.Method != "GET" && r.Method != "POST" {
104116
http.Error(w, fmt.Sprintf("method %v is not allowed", r.Method), http.StatusMethodNotAllowed)
@@ -140,8 +152,8 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
140152
h.handleFakerTree(w, r)
141153
case strings.HasPrefix(p, "/api/search"):
142154
h.getSearchResults(w, r)
143-
case strings.HasPrefix(p, "/health"):
144-
handleHealth(w, r)
155+
case strings.HasPrefix(p, h.healthPath) && h.healthHandler != nil:
156+
h.healthHandler.ServeHTTP(w, r)
145157
case h.fileServer != nil:
146158
if r.Method != "GET" {
147159
http.Error(w, fmt.Sprintf("method %v is not allowed", r.Method), http.StatusMethodNotAllowed)
@@ -293,22 +305,3 @@ func getPageInfo(r *http.Request) (index int, limit int, err error) {
293305
}
294306
return
295307
}
296-
297-
func handleHealth(w http.ResponseWriter, r *http.Request) {
298-
if r.Method != http.MethodGet {
299-
w.WriteHeader(http.StatusMethodNotAllowed)
300-
return
301-
}
302-
303-
if strings.HasSuffix(r.URL.Path, "/health/live") {
304-
w.Header().Set("Content-Type", "application/json")
305-
w.WriteHeader(http.StatusOK)
306-
_, _ = w.Write([]byte(`{"status":"alive"}`))
307-
} else if strings.HasSuffix(r.URL.Path, "/health/ready") {
308-
w.Header().Set("Content-Type", "application/json")
309-
w.WriteHeader(http.StatusOK)
310-
_, _ = w.Write([]byte(`{"status":"ready"}`))
311-
} else {
312-
http.NotFound(w, r)
313-
}
314-
}

api/handler_test.go

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api_test
33
import (
44
"mokapi/api"
55
"mokapi/config/static"
6+
"mokapi/health"
67
"mokapi/providers/openapi"
78
"mokapi/runtime"
89
"mokapi/runtime/runtimetest"
@@ -218,54 +219,32 @@ func TestHandler_Health(t *testing.T) {
218219
name: "POST is not allowed",
219220
cfg: &static.Config{},
220221
test: func(t *testing.T, h http.Handler) {
221-
r := httptest.NewRequest(http.MethodPatch, "http://foo.api/health/live", nil)
222+
r := httptest.NewRequest(http.MethodPatch, "http://foo.api/health", nil)
222223
rr := httptest.NewRecorder()
223224
h.ServeHTTP(rr, r)
224225
require.Equal(t, http.StatusMethodNotAllowed, rr.Code)
225226
},
226227
},
227228
{
228-
name: "GET /health/live",
229+
name: "GET /health",
229230
cfg: &static.Config{},
230231
test: func(t *testing.T, h http.Handler) {
231-
r := httptest.NewRequest(http.MethodGet, "http://foo.api/health/live", nil)
232+
r := httptest.NewRequest(http.MethodGet, "http://foo.api/health", nil)
232233
rr := httptest.NewRecorder()
233234
h.ServeHTTP(rr, r)
234235
require.Equal(t, http.StatusOK, rr.Code)
235-
require.Equal(t, `{"status":"alive"}`, rr.Body.String())
236-
},
237-
},
238-
{
239-
name: "GET /health/ready",
240-
cfg: &static.Config{},
241-
test: func(t *testing.T, h http.Handler) {
242-
r := httptest.NewRequest(http.MethodGet, "http://foo.api/health/ready", nil)
243-
rr := httptest.NewRecorder()
244-
h.ServeHTTP(rr, r)
245-
require.Equal(t, http.StatusOK, rr.Code)
246-
require.Equal(t, `{"status":"ready"}`, rr.Body.String())
236+
require.Equal(t, `{"status":"healthy"}`, rr.Body.String())
247237
},
248238
},
249239
{
250240
name: "use path but request does not adapt",
251241
cfg: &static.Config{Api: static.Api{Path: "/foo"}},
252242
test: func(t *testing.T, h http.Handler) {
253-
r := httptest.NewRequest(http.MethodGet, "http://foo.api/health/ready", nil)
254-
rr := httptest.NewRecorder()
255-
h.ServeHTTP(rr, r)
256-
require.Equal(t, http.StatusOK, rr.Code)
257-
require.Equal(t, `{"status":"ready"}`, rr.Body.String())
258-
},
259-
},
260-
{
261-
name: "use path and request adapt",
262-
cfg: &static.Config{Api: static.Api{Path: "/foo"}},
263-
test: func(t *testing.T, h http.Handler) {
264-
r := httptest.NewRequest(http.MethodGet, "http://foo.api/foo/health/ready", nil)
243+
r := httptest.NewRequest(http.MethodGet, "http://foo.api/health", nil)
265244
rr := httptest.NewRecorder()
266245
h.ServeHTTP(rr, r)
267246
require.Equal(t, http.StatusOK, rr.Code)
268-
require.Equal(t, `{"status":"ready"}`, rr.Body.String())
247+
require.Equal(t, `{"status":"healthy"}`, rr.Body.String())
269248
},
270249
},
271250
}
@@ -277,6 +256,7 @@ func TestHandler_Health(t *testing.T) {
277256
t.Parallel()
278257

279258
h := api.New(runtime.New(tc.cfg), tc.cfg.Api)
259+
h.RegisterHealthHandler("/health", health.New(static.Health{}))
280260
tc.test(t, h)
281261
})
282262
}

cmd/mokapi/main_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ api:
8484
enabled: true
8585
indexPath: ""
8686
inMemory: false
87+
health:
88+
enabled: true
89+
path: /health
90+
port: 8080
91+
log: false
8792
rootCaCert: ""
8893
rootCaKey: ""
8994
configs: []

config/dynamic/provider/git/git.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"time"
1616

1717
"github.com/go-git/go-git/v5"
18-
"github.com/go-git/go-git/v5/config"
1918
"github.com/go-git/go-git/v5/plumbing"
2019
"github.com/go-git/go-git/v5/plumbing/transport/client"
2120
"github.com/go-git/go-git/v5/plumbing/transport/http"
@@ -271,9 +270,9 @@ func pull(r *repository) {
271270
if r.repo == nil {
272271
return
273272
}
274-
err := r.repo.Fetch(&git.FetchOptions{RefSpecs: []config.RefSpec{"refs/*:refs/*", "HEAD:refs/heads/HEAD"}})
273+
err := r.repo.Fetch(&git.FetchOptions{})
275274
if errors.Is(err, git.ErrForceNeeded) {
276-
err = r.repo.Fetch(&git.FetchOptions{RefSpecs: []config.RefSpec{"+refs/*:refs/*", "HEAD:refs/heads/HEAD"}})
275+
err = r.repo.Fetch(&git.FetchOptions{})
277276
}
278277
if err != nil {
279278
if !errors.Is(err, git.NoErrAlreadyUpToDate) {

config/static/static_config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Config struct {
1818
ConfigFile string `json:"-" yaml:"-" flag:"config-file"`
1919
Providers Providers `json:"providers" yaml:"providers"`
2020
Api Api `json:"api" yaml:"api"`
21+
Health Health `json:"health" yaml:"health"`
2122
RootCaCert tls.FileOrContent `json:"rootCaCert" yaml:"rootCaCert" name:"root-ca-cert"`
2223
RootCaKey tls.FileOrContent `json:"rootCaKey" yaml:"rootCaKey" name:"root-ca-cert"`
2324
Configs Configs `json:"configs" yaml:"configs" explode:"config"`
@@ -39,6 +40,10 @@ func NewConfig() *Config {
3940
cfg.Api.Dashboard = true
4041
cfg.Api.Search.Enabled = true
4142

43+
cfg.Health.Enabled = true
44+
cfg.Health.Port = 8080
45+
cfg.Health.Path = "/health"
46+
4247
cfg.Providers.File.SkipPrefix = []string{"_"}
4348
cfg.Event.Store = map[string]Store{"default": {Size: 100}}
4449
cfg.DataGen.OptionalProperties = "0.85"
@@ -286,3 +291,10 @@ func (fc *FileConfig) Set(v any) error {
286291
}
287292
return fmt.Errorf("expected string, got %T", v)
288293
}
294+
295+
type Health struct {
296+
Enabled bool `yaml:"enabled" json:"enabled"`
297+
Path string `yaml:"path" json:"path"`
298+
Port int `yaml:"port" json:"port"`
299+
Log bool `yaml:"log" json:"log"`
300+
}

health/http_handler.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package health
2+
3+
import (
4+
"fmt"
5+
"mokapi/config/static"
6+
"mokapi/lib"
7+
"net/http"
8+
"net/url"
9+
10+
log "github.com/sirupsen/logrus"
11+
)
12+
13+
type handler struct {
14+
path string
15+
log bool
16+
}
17+
18+
func New(cfg static.Health) http.Handler {
19+
return &handler{path: healthPath(cfg), log: cfg.Log}
20+
}
21+
22+
func BuildUrl(cfg static.Health) (*url.URL, error) {
23+
s := fmt.Sprintf("http://:%v%v", cfg.Port, healthPath(cfg))
24+
return url.Parse(s)
25+
}
26+
27+
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
28+
if r.Method != "GET" {
29+
w.Header().Set("Allow", http.MethodGet)
30+
http.Error(w, fmt.Sprintf("method %v is not allowed", r.Method), http.StatusMethodNotAllowed)
31+
if h.log {
32+
log.Warnf("healthcheck: method not allowed: %v %v", r.Method, lib.GetUrl(r))
33+
}
34+
return
35+
}
36+
37+
switch r.URL.Path {
38+
case h.path:
39+
w.Header().Set("Content-Type", "application/json")
40+
w.WriteHeader(http.StatusOK)
41+
_, _ = w.Write([]byte(`{"status":"healthy"}`))
42+
if h.log {
43+
log.Infof("healthcheck: %v %v: healthy", r.Method, lib.GetUrl(r))
44+
}
45+
default:
46+
http.NotFound(w, r)
47+
if h.log {
48+
log.Debugf("healthcheck: not found: %v %v", r.Method, lib.GetUrl(r))
49+
}
50+
}
51+
}
52+
53+
func healthPath(cfg static.Health) string {
54+
path := "/health"
55+
if cfg.Path != "" {
56+
path = cfg.Path
57+
}
58+
return path
59+
}

0 commit comments

Comments
 (0)