Skip to content

Commit 5a54ce8

Browse files
authored
Update Makefile to load venv on every command closes #433 (#455)
Signed-off-by: Mihai Criveti <[email protected]>
1 parent ed78c45 commit 5a54ce8

File tree

2 files changed

+146
-37
lines changed

2 files changed

+146
-37
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
docs/pstats.png
2+
mcp.prof
3+
mcp.pstats
14
.depsorter_cache.json
25
.depupdate.*
36
update_dependencies.py

Makefile

Lines changed: 143 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ os-deps: $(OS_DEPS_SCRIPT)
6464
@bash $(OS_DEPS_SCRIPT)
6565

6666

67+
# -----------------------------------------------------------------------------
68+
# 🔧 HELPER SCRIPTS
69+
# -----------------------------------------------------------------------------
70+
# Helper to ensure a Python package is installed in venv
71+
define ensure_pip_package
72+
@test -d "$(VENV_DIR)" || $(MAKE) venv
73+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
74+
python3 -m pip show $(1) >/dev/null 2>&1 || \
75+
python3 -m pip install -q $(1)"
76+
endef
77+
6778
# =============================================================================
6879
# 🌱 VIRTUAL ENVIRONMENT & INSTALLATION
6980
# =============================================================================
@@ -291,9 +302,23 @@ pip-licenses:
291302
@echo "📜 License inventory written to $(LICENSES_MD)"
292303

293304
scc:
305+
@command -v scc >/dev/null 2>&1 || { \
306+
echo "❌ scc not installed."; \
307+
echo "💡 Install with:"; \
308+
echo " • macOS: brew install scc"; \
309+
echo " • Linux: Download from https://github.com/boyter/scc/releases"; \
310+
exit 1; \
311+
}
294312
@scc --by-file -i py,sh .
295313

296314
scc-report:
315+
@command -v scc >/dev/null 2>&1 || { \
316+
echo "❌ scc not installed."; \
317+
echo "💡 Install with:"; \
318+
echo " • macOS: brew install scc"; \
319+
echo " • Linux: Download from https://github.com/boyter/scc/releases"; \
320+
exit 1; \
321+
}
297322
@mkdir -p $(dir $(METRICS_MD))
298323
@printf "# Lines of Code Report\n\n" > $(METRICS_MD)
299324
@scc . --format=html-table >> $(METRICS_MD)
@@ -318,16 +343,12 @@ endif
318343
.PHONY: docs
319344
docs: images sbom
320345
@echo "📚 Generating documentation with handsdown..."
321-
uv handsdown --external https://github.com/yourorg/$(PROJECT_NAME)/ \
322-
-o $(DOCS_DIR)/docs \
323-
-n app --name "$(PROJECT_NAME)" --cleanup
324-
325-
@echo "🔧 Rewriting GitHub links..."
326-
@find $(DOCS_DIR)/docs/app -type f \
327-
-exec sed $(SED_INPLACE) 's#https://github.com/yourorg#https://github.com/ibm/mcp-context-forge#g' {} +
328-
329-
@sed $(SED_INPLACE) 's#https://github.com/yourorg#https://github.com/ibm/mcp-context-forge#g' \
330-
$(DOCS_DIR)/docs/README.md
346+
@test -d "$(VENV_DIR)" || $(MAKE) venv
347+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
348+
python3 -m pip install -q handsdown && \
349+
python3 -m handsdown --external https://github.com/IBM/mcp-context-forge/ \
350+
-o $(DOCS_DIR)/docs \
351+
-n app --name '$(PROJECT_NAME)' --cleanup"
331352

332353
@cp README.md $(DOCS_DIR)/docs/index.md
333354
@echo "✅ Docs ready in $(DOCS_DIR)/docs"
@@ -336,14 +357,26 @@ docs: images sbom
336357
images:
337358
@echo "🖼️ Generating documentation diagrams..."
338359
@mkdir -p $(DOCS_DIR)/docs/design/images
339-
@code2flow mcpgateway/ --output $(DOCS_DIR)/docs/design/images/code2flow.dot || true
340-
@dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black $(DOCS_DIR)/docs/design/images/code2flow.dot -o $(DOCS_DIR)/docs/design/images/code2flow.svg || true
341-
@/bin/bash -c "source $(VENV_DIR)/bin/activate && python3 -m pip install snakefood3"
342-
@/bin/bash -c "source $(VENV_DIR)/bin/activate && python3 -m snakefood3 . mcpgateway > snakefood.dot"
343-
@dot -Tpng -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=12 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=10 -Efontcolor=black snakefood.dot -o $(DOCS_DIR)/docs/design/images/snakefood.png || true
344-
@pyreverse --colorized mcpgateway || true
345-
@dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black packages.dot -o $(DOCS_DIR)/docs/design/images/packages.svg || true
346-
@dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black classes.dot -o $(DOCS_DIR)/docs/design/images/classes.svg || true
360+
@test -d "$(VENV_DIR)" || $(MAKE) venv
361+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
362+
python3 -m pip install -q code2flow && \
363+
$(VENV_DIR)/bin/code2flow mcpgateway/ --output $(DOCS_DIR)/docs/design/images/code2flow.dot || true"
364+
@command -v dot >/dev/null 2>&1 || { \
365+
echo "⚠️ Graphviz (dot) not installed - skipping diagram generation"; \
366+
echo "💡 Install with: brew install graphviz (macOS) or apt-get install graphviz (Linux)"; \
367+
} && \
368+
dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black $(DOCS_DIR)/docs/design/images/code2flow.dot -o $(DOCS_DIR)/docs/design/images/code2flow.svg || true
369+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
370+
python3 -m pip install -q snakefood3 && \
371+
python3 -m snakefood3 . mcpgateway > snakefood.dot"
372+
@command -v dot >/dev/null 2>&1 && \
373+
dot -Tpng -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=12 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=10 -Efontcolor=black snakefood.dot -o $(DOCS_DIR)/docs/design/images/snakefood.png || true
374+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
375+
python3 -m pip install -q pylint && \
376+
$(VENV_DIR)/bin/pyreverse --colorized mcpgateway || true"
377+
@command -v dot >/dev/null 2>&1 && \
378+
dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black packages.dot -o $(DOCS_DIR)/docs/design/images/packages.svg || true && \
379+
dot -Tsvg -Gbgcolor=transparent -Gfontname="Arial" -Nfontname="Arial" -Nfontsize=14 -Nfontcolor=black -Nfillcolor=white -Nshape=box -Nstyle="filled,rounded" -Ecolor=gray -Efontname="Arial" -Efontsize=14 -Efontcolor=black classes.dot -o $(DOCS_DIR)/docs/design/images/classes.svg || true
347380
@rm -f packages.dot classes.dot snakefood.dot || true
348381

349382
# =============================================================================
@@ -473,9 +506,13 @@ fawltydeps: ## 🏗️ Dependency sanity
473506
@$(VENV_DIR)/bin/fawltydeps --detailed --exclude 'docs/**' . || true
474507

475508
wily: ## 📈 Maintainability report
509+
@echo "📈 Maintainability report..."
510+
@test -d "$(VENV_DIR)" || $(MAKE) venv
476511
@git stash --quiet
477-
@wily build -n 10 . > /dev/null || true
478-
@wily report . || true
512+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
513+
python3 -m pip install -q wily && \
514+
python3 -m wily build -n 10 . > /dev/null || true && \
515+
python3 -m wily report . || true"
479516
@git stash pop --quiet
480517

481518
pyre: ## 🧠 Facebook Pyre analysis
@@ -485,15 +522,28 @@ pyrefly: ## 🧠 Facebook Pyrefly analysis (faster,
485522
@$(VENV_DIR)/bin/pyrefly check mcpgateway
486523

487524
depend: ## 📦 List dependencies
488-
pdm list --freeze
525+
@echo "📦 List dependencies"
526+
@test -d "$(VENV_DIR)" || $(MAKE) venv
527+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
528+
python3 -m pip install -q pdm && \
529+
python3 -m pdm list --freeze"
489530

490531
snakeviz: ## 🐍 Interactive profile visualiser
491-
@python3 -m cProfile -o mcp.prof app/server.py && snakeviz mcp.prof --server
532+
@echo "🐍 Interactive profile visualiser..."
533+
@test -d "$(VENV_DIR)" || $(MAKE) venv
534+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
535+
python3 -m pip install -q snakeviz && \
536+
python3 -m cProfile -o mcp.prof mcpgateway/main.py && \
537+
python3 -m snakeviz mcp.prof --server"
492538

493539
pstats: ## 📊 Static call-graph image
494-
@python3 -m cProfile -o mcp.pstats app/server.py && \
495-
gprof2dot -w -e 3 -n 3 -s -f pstats mcp.pstats | \
496-
dot -Tpng -o $(DOCS_DIR)/pstats.png
540+
@echo "📊 Static call-graph image"
541+
@test -d "$(VENV_DIR)" || $(MAKE) venv
542+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
543+
python3 -m pip install -q gprof2dot && \
544+
python3 -m cProfile -o mcp.pstats mcpgateway/main.py && \
545+
$(VENV_DIR)/bin/gprof2dot -w -e 3 -n 3 -s -f pstats mcp.pstats | \
546+
dot -Tpng -o $(DOCS_DIR)/pstats.png"
497547

498548
spellcheck-sort: .spellcheck-en.txt ## 🔤 Sort spell-list
499549
sort -d -f -o $< $<
@@ -563,10 +613,24 @@ grype-install:
563613
@curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
564614

565615
grype-scan:
616+
@command -v grype >/dev/null 2>&1 || { \
617+
echo "❌ grype not installed."; \
618+
echo "💡 Install with:"; \
619+
echo " • curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin"; \
620+
echo " • Or run: make grype-install"; \
621+
exit 1; \
622+
}
566623
@echo "🔍 Grype vulnerability scan..."
567624
@grype $(IMG):latest --scope all-layers --only-fixed
568625

569626
grype-sarif:
627+
@command -v grype >/dev/null 2>&1 || { \
628+
echo "❌ grype not installed."; \
629+
echo "💡 Install with:"; \
630+
echo " • curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin"; \
631+
echo " • Or run: make grype-install"; \
632+
exit 1; \
633+
}
570634
@echo "📄 Generating Grype SARIF report..."
571635
@grype $(IMG):latest --scope all-layers --output sarif --file grype-results.sarif
572636

@@ -587,22 +651,31 @@ LINTERS += yamllint jsonlint tomllint
587651
.PHONY: yamllint jsonlint tomllint
588652

589653
yamllint: ## 📑 YAML linting
590-
@command -v yamllint >/dev/null 2>&1 || { \
591-
echo '❌ yamllint not installed ➜ pip install yamllint'; exit 1; }
592-
@echo '📑 yamllint ...' && $(VENV_DIR)/bin/yamllint -c .yamllint .
654+
@echo '📑 yamllint ...'
655+
$(call ensure_pip_package,yamllint)
656+
@test -d "$(VENV_DIR)" || $(MAKE) venv
657+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
658+
python3 -m pip install -q yamllint 2>/dev/null || true"
659+
@$(VENV_DIR)/bin/yamllint -c .yamllint .
593660

594661
jsonlint: ## 📑 JSON validation (jq)
595662
@command -v jq >/dev/null 2>&1 || { \
596-
echo '❌ jq not installed ➜ sudo apt-get install jq'; exit 1; }
663+
echo "❌ jq not installed."; \
664+
echo "💡 Install with:"; \
665+
echo " • macOS: brew install jq"; \
666+
echo " • Linux: sudo apt-get install jq"; \
667+
exit 1; \
668+
}
597669
@echo '📑 jsonlint (jq) ...'
598670
@find . -type f -name '*.json' -not -path './node_modules/*' -print0 \
599671
| xargs -0 -I{} sh -c 'jq empty "{}"' \
600672
&& echo '✅ All JSON valid'
601673

602674
tomllint: ## 📑 TOML validation (tomlcheck)
603-
@command -v tomlcheck >/dev/null 2>&1 || { \
604-
echo '❌ tomlcheck not installed ➜ pip install tomlcheck'; exit 1; }
605675
@echo '📑 tomllint (tomlcheck) ...'
676+
@test -d "$(VENV_DIR)" || $(MAKE) venv
677+
@/bin/bash -c "source $(VENV_DIR)/bin/activate && \
678+
python3 -m pip install -q tomlcheck 2>/dev/null || true"
606679
@find . -type f -name '*.toml' -print0 \
607680
| xargs -0 -I{} $(VENV_DIR)/bin/tomlcheck "{}"
608681

@@ -666,11 +739,25 @@ osv-install: ## Install/upgrade osv-scanner
666739

667740
# ─────────────── Source directory scan ────────────────────────────────────────
668741
osv-scan-source:
742+
@command -v osv-scanner >/dev/null 2>&1 || { \
743+
echo "❌ osv-scanner not installed."; \
744+
echo "💡 Install with:"; \
745+
echo " • go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest"; \
746+
echo " • Or run: make osv-install"; \
747+
exit 1; \
748+
}
669749
@echo "🔍 osv-scanner source scan..."
670750
@osv-scanner scan source --recursive .
671751

672752
# ─────────────── Container image scan ─────────────────────────────────────────
673753
osv-scan-image:
754+
@command -v osv-scanner >/dev/null 2>&1 || { \
755+
echo "❌ osv-scanner not installed."; \
756+
echo "💡 Install with:"; \
757+
echo " • go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest"; \
758+
echo " • Or run: make osv-install"; \
759+
exit 1; \
760+
}
674761
@echo "🔍 osv-scanner image scan..."
675762
@CONTAINER_CLI=$$(command -v docker || command -v podman) ; \
676763
if [ -n "$$CONTAINER_CLI" ]; then \
@@ -804,7 +891,15 @@ trivy-install:
804891
@curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
805892

806893
trivy:
807-
@systemctl --user enable --now podman.socket
894+
@command -v trivy >/dev/null 2>&1 || { \
895+
echo "❌ trivy not installed."; \
896+
echo "💡 Install with:"; \
897+
echo " • macOS: brew install trivy"; \
898+
echo " • Linux: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin"; \
899+
echo " • Or run: make trivy-install"; \
900+
exit 1; \
901+
}
902+
@systemctl --user enable --now podman.socket 2>/dev/null || true
808903
@echo "🔎 trivy vulnerability scan..."
809904
@trivy --format table --severity HIGH,CRITICAL image $(IMG)
810905

@@ -813,8 +908,13 @@ trivy:
813908
DOCKLE_IMAGE ?= $(IMG):latest # mcpgateway/mcpgateway:latest from your build
814909
dockle:
815910
@echo "🔎 dockle scan (tar mode) on $(DOCKLE_IMAGE)..."
816-
@command -v dockle >/dev/null || { \
817-
echo '❌ Dockle not installed. See https://github.com/goodwithtech/dockle'; exit 1; }
911+
@command -v dockle >/dev/null 2>&1 || { \
912+
echo "❌ dockle not installed."; \
913+
echo "💡 Install with:"; \
914+
echo " • macOS: brew install goodwithtech/r/dockle"; \
915+
echo " • Linux: Download from https://github.com/goodwithtech/dockle/releases"; \
916+
exit 1; \
917+
}
818918

819919
# Pick docker or podman-whichever is on PATH
820920
@CONTAINER_CLI=$$(command -v docker || command -v podman) ; \
@@ -2191,11 +2291,17 @@ shell-linters-install: ## 🔧 Install shellcheck, shfmt, bashate
21912291

21922292
shell-lint: shell-linters-install ## 🔍 Run shfmt, ShellCheck & bashate
21932293
@echo "🔍 Running shfmt (diff-only)..."
2194-
@shfmt -d -i 4 -ci $(SHELL_SCRIPTS) || true
2294+
@command -v shfmt >/dev/null 2>&1 || { \
2295+
echo "⚠️ shfmt not installed - skipping"; \
2296+
echo "💡 Install with: go install mvdan.cc/sh/v3/cmd/shfmt@latest"; \
2297+
} && shfmt -d -i 4 -ci $(SHELL_SCRIPTS) || true
21952298
@echo "🔍 Running ShellCheck..."
2196-
@shellcheck $(SHELL_SCRIPTS) || true
2299+
@command -v shellcheck >/dev/null 2>&1 || { \
2300+
echo "⚠️ shellcheck not installed - skipping"; \
2301+
echo "💡 Install with: brew install shellcheck (macOS) or apt-get install shellcheck (Linux)"; \
2302+
} && shellcheck $(SHELL_SCRIPTS) || true
21972303
@echo "🔍 Running bashate..."
2198-
@$(VENV_DIR)/bin/bashate -C $(SHELL_SCRIPTS) || true
2304+
@$(VENV_DIR)/bin/bashate $(SHELL_SCRIPTS) || true
21992305
@echo "✅ Shell lint complete."
22002306

22012307

0 commit comments

Comments
 (0)