Last active
March 9, 2026 11:04
-
-
Save DmitrySkibitsky/4359ff051f6c6a04f908184bd484ffc8 to your computer and use it in GitHub Desktop.
mago (Symfony)
This file contains hidden or 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
| FROM alpine:3.21 | |
| ARG MAGO_VERSION=latest | |
| ARG TARGETARCH | |
| RUN apk add --no-cache ca-certificates curl | |
| # Resolve version and download the mago binary for the target architecture. | |
| # Asset naming convention: mago-{VERSION}-{ARCH}.tar.gz | |
| RUN set -eux; \ | |
| if [ "$MAGO_VERSION" = "latest" ]; then \ | |
| MAGO_VERSION="$(curl -fsSL https://api.github.com/repos/carthage-software/mago/releases/latest \ | |
| | grep -oP '"tag_name":\s*"\K[^"]+')"; \ | |
| fi; \ | |
| echo "Resolved mago version: ${MAGO_VERSION}"; \ | |
| case "$TARGETARCH" in \ | |
| amd64) ARCH="x86_64-unknown-linux-musl" ;; \ | |
| arm64) ARCH="aarch64-unknown-linux-musl" ;; \ | |
| *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \ | |
| esac; \ | |
| mkdir -p /tmp/mago-extract; \ | |
| curl -fsSL \ | |
| "https://github.com/carthage-software/mago/releases/download/${MAGO_VERSION}/mago-${MAGO_VERSION}-${ARCH}.tar.gz" \ | |
| | tar -xz -C /tmp/mago-extract; \ | |
| echo "Archive contents:"; \ | |
| find /tmp/mago-extract -print; \ | |
| MAGO_BIN="$(find /tmp/mago-extract -type f -name 'mago' | head -1)"; \ | |
| if [ -z "$MAGO_BIN" ]; then \ | |
| echo "ERROR: mago binary not found in archive"; \ | |
| find /tmp/mago-extract -print; \ | |
| exit 1; \ | |
| fi; \ | |
| mv "$MAGO_BIN" /usr/local/bin/mago; \ | |
| rm -rf /tmp/mago-extract; \ | |
| chmod +x /usr/local/bin/mago; \ | |
| mago --version | |
| WORKDIR /app | |
| ENTRYPOINT ["mago"] | |
This file contains hidden or 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
| # ───────────────────────────────────────────────────────────────────────────── | |
| MAGO_IMAGE := mago:latest | |
| MAGO_DOCKERFILE := docker/mago/Dockerfile | |
| _SERVICE_ABS := $(abspath $(_SERVICE_DIR)) | |
| _FILE_ARG := $(if $(FILE),$(patsubst $(_SERVICE_ABS)/%,%,$(FILE)),) | |
| _MAGO_ARGS := $(if $(_FILE_ARG),$(CMD) $(_FILE_ARG),$(CMD)) | |
| # Mago targets | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| mago-build: ## Build the mago Docker image (run once, or after version bump) | |
| docker build \ | |
| --build-arg TARGETARCH="$$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')" \ | |
| -t $(MAGO_IMAGE) \ | |
| -f $(MAGO_DOCKERFILE) \ | |
| docker/mago | |
| mago: ## Run mago. SERVICE=auth or projects, CMD=lint/fmt/analyze/check, FILE=<abs path> | |
| @if ! docker image inspect $(MAGO_IMAGE) > /dev/null 2>&1; then \ | |
| echo " Image $(MAGO_IMAGE) not found -- building..."; \ | |
| $(MAKE) mago-build; \ | |
| fi | |
| docker run --rm \ | |
| -v "$(_SERVICE_ABS):/app" \ | |
| -w /app \ | |
| $(MAGO_IMAGE) $(_MAGO_ARGS) |
This file contains hidden or 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
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Mago configuration for the Auth service (PHP 8.4 / Symfony 8) | |
| # Strict typing enforcement is intentional — keep it that way. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| php-version = "8.4" | |
| [source] | |
| # Analyse application code and tests; vendor is context-only (includes). | |
| paths = ["src", "tests"] | |
| includes = ["vendor"] | |
| excludes = ["var/**", "var/cache/**"] | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Linter | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| [linter] | |
| # Symfony integration enables framework-aware rules (service naming, etc.) | |
| integrations = ["symfony"] | |
| baseline = "lint-baseline.toml" | |
| [linter.rules] | |
| # ── Strict types ────────────────────────────────────────────────────────────── | |
| # Every PHP file must declare strict_types=1. | |
| strict-types = { level = "error" } | |
| # ── Type hints consistency ──────────────────────────────────────────────────── | |
| # Type hints must use lowercase built-in names (int, string, bool, etc.) | |
| lowercase-type-hint = { level = "error" } | |
| # Nullable params must use explicit ?Type syntax (PHP 8.0+ style) | |
| explicit-nullable-param = { level = "error" } | |
| # ── Code quality ────────────────────────────────────────────────────────────── | |
| no-nested-ternary = { level = "error" } | |
| no-closing-tag = { level = "error" } | |
| no-goto = { level = "error" } | |
| no-eval = { level = "error" } | |
| # Shorthand ternary (?:) can hide bugs — use explicit conditions. | |
| no-shorthand-ternary = { level = "warning" } | |
| # No error suppression with @ | |
| no-error-control-operator = { level = "error" } | |
| # No global state | |
| no-global = { level = "error" } | |
| # Avoid empty catch blocks — at minimum log or rethrow. | |
| no-empty-catch-clause = { level = "warning" } | |
| # Empty loop bodies are usually bugs. | |
| no-empty-loop = { level = "warning" } | |
| # Avoid useless else after return / throw / continue. | |
| no-else-clause = { level = "warning" } | |
| # Inline variable return is redundant ($x = ...; return $x;). | |
| inline-variable-return = { level = "warning" } | |
| # Prefer first-class callable syntax (PHP 8.1+) | |
| prefer-first-class-callable = { level = "warning" } | |
| # Prefer arrow functions for short closures (reduces boilerplate) | |
| prefer-arrow-function = { level = "warning", exclude = ["tests/"] } | |
| # Static closures when $this is not used | |
| prefer-static-closure = { level = "warning", exclude = ["tests/"] } | |
| # ── Complexity ──────────────────────────────────────────────────────────────── | |
| cyclomatic-complexity = { threshold = 10, level = "warning" } | |
| # ── Redundancy detection ────────────────────────────────────────────────────── | |
| no-redundant-nullsafe = { level = "warning" } | |
| no-redundant-parentheses = { level = "warning" } | |
| no-redundant-string-concat = { level = "warning" } | |
| no-redundant-use = { level = "warning" } | |
| no-redundant-final = { level = "warning" } | |
| no-redundant-readonly = { level = "warning" } | |
| no-redundant-block = { level = "warning" } | |
| no-redundant-continue = { level = "warning" } | |
| no-redundant-literal-return = { level = "warning" } | |
| no-redundant-isset = { level = "warning" } | |
| no-redundant-math = { level = "warning" } | |
| # ── Debug / security ───────────────────────────────────────────────────────── | |
| no-debug-symbols = { level = "error" } | |
| no-literal-password = { level = "error" } | |
| # Strict comparison (=== / !==) everywhere | |
| identity-comparison = { level = "error" } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Formatter (PSR-12 base, Symfony-style overrides) | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| [formatter] | |
| preset = "psr-12" | |
| print-width = 120 | |
| tab-width = 4 | |
| use-tabs = false | |
| single-quote = true | |
| trailing-comma = true | |
| # Break each named argument in attributes onto its own line | |
| always-break-attribute-named-argument-lists = true | |
| preserve-breaking-attribute-list = true | |
| always-break-named-arguments-list = true | |
| # Symfony / PSR-12 brace style | |
| control-brace-style = "same-line" | |
| function-brace-style = "next-line" | |
| method-brace-style = "next-line" | |
| classlike-brace-style = "next-line" | |
| # Blank lines around namespace and use blocks | |
| empty-line-after-opening-tag = true | |
| empty-line-after-namespace = true | |
| empty-line-after-use = true | |
| # Keep `use` statements sorted and split by type (class vs function vs const) | |
| sort-uses = true | |
| separate-use-types = true | |
| expand-use-groups = true | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Analyzer (maximum strictness) | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| [analyzer] | |
| baseline = "analysis-baseline.toml" | |
| # Unused code detection | |
| find-unused-expressions = true | |
| find-unused-definitions = true | |
| analyze-dead-code = true | |
| find-unused-parameters = true | |
| # Exception handling verification | |
| check-throws = true | |
| # Enforce `override` attribute where applicable (PHP 8.3+) | |
| check-missing-override = true | |
| # ── Type hint enforcement (core goal) ───────────────────────────────────────── | |
| # Report every missing type hint: params, return types, properties. | |
| check-missing-type-hints = true | |
| check-closure-missing-type-hints = true | |
| check-arrow-function-missing-type-hints = true | |
| # Enforce `final` on classes that are not explicitly designed for extension. | |
| # Disable per-class with a `@api` or `@internal` docblock if needed. | |
| enforce-class-finality = true | |
| # Require @api or @internal phpdoc on public API surface (enable when stable) | |
| require-api-or-internal = false | |
| # ── Strict runtime-safety checks ───────────────────────────────────────────── | |
| strict-list-index-checks = true | |
| no-boolean-literal-comparison = true | |
| allow-possibly-undefined-array-keys = false | |
| trust-existence-checks = false | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment