diff --git a/kocal/symfony-app-pack/1.0/.github/dependabot.yaml b/kocal/symfony-app-pack/1.0/.github/dependabot.yaml new file mode 100644 index 00000000..e22c9da3 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/.github/dependabot.yaml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "composer" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/kocal/symfony-app-pack/1.0/.github/workflows/ci.yaml b/kocal/symfony-app-pack/1.0/.github/workflows/ci.yaml new file mode 100644 index 00000000..bc9be145 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/.github/workflows/ci.yaml @@ -0,0 +1,41 @@ +name: CI + +defaults: + run: + shell: bash + +on: + pull_request: + types: [ opened, synchronize, reopened, ready_for_review ] + push: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + qa: + if: ${{ ! github.event.pull_request.draft }} + name: Quality Assurance + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + extensions: ctype, iconv, mbstring + tools: symfony + + - name: Start Docker containers + run: docker compose up -d --wait + + - name: Install project + run: make app.install + + - name: QA + run: make qa diff --git a/kocal/symfony-app-pack/1.0/.twig-cs-fixer.php b/kocal/symfony-app-pack/1.0/.twig-cs-fixer.php new file mode 100644 index 00000000..8afee1f9 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/.twig-cs-fixer.php @@ -0,0 +1,10 @@ +addStandard(new TwigCsFixer\Standard\Symfony()); + +$config = new TwigCsFixer\Config\Config(); +$config->setCacheFile(__DIR__.'/tools/.cache/twig-cs-fixer'); +$config->setRuleset($ruleset); + +return $config; diff --git a/kocal/symfony-app-pack/1.0/Makefile b/kocal/symfony-app-pack/1.0/Makefile new file mode 100644 index 00000000..9ca53377 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/Makefile @@ -0,0 +1,180 @@ +ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +include $(ROOT_DIR)/tools/make/text.mk +include $(ROOT_DIR)/tools/make/help.mk +include $(ROOT_DIR)/tools/make/os.mk +include $(ROOT_DIR)/tools/make/git.mk + +.DEFAULT_GOAL := help + +# Executables +SF := symfony +SF_PROXY = $(shell $(SF) local:proxy:url) +SF_CONSOLE := $(SF) console +PHP := $(SF) php +COMPOSER := $(SF) composer + +UID := $(shell id -u) +GID := $(shell id -g) +DC := USER_ID=$(UID) GROUP_ID=$(GID) docker compose --env-file /dev/null + +## Install everything needed to start the project +install: + $(SF) local:server:ca:install + $(MAKE) start + $(MAKE) app.install + +## Start the environment +start: + $(DC) up -d + $(SF) proxy:start + $(SF) serve + +## Stop the environment +stop: + $(DC) kill + +## Stop and delete the environment and project data (database, logs, etc.) +delete: + $(DC) down -v --remove-orphans + +## App - Install the application +app.install: + @$(call action, Installing PHP dependencies...) + $(COMPOSER) install --prefer-dist + + @$(call action, Running DB migrations...) + $(SF_CONSOLE) doctrine:migrations:migrate --no-interaction --all-or-nothing + +## App - Install the application (alias to "make app.install") +app.update: app.install + +###### +# QA # +###### + +## QA - Run all QA checks +qa: archi refactor cs lint phpstan test + +## QA - Run all QA checks and fix issues +qa.fix: archi refactor.fix cs.fix lint.fix phpstan test + +######### +# Archi # +######### + +## Architecture - Run architecture checks +archi: archi.back + +## Architecture - Run architecture checks for backend +archi.back: + $(PHP) vendor/bin/deptrac --report-uncovered --fail-on-uncovered + +############ +# Refactor # +############ + +## Refactor - Run all refactor checks +refactor: refactor.back + +## Refactor - Run all refactor checks and fix issues +refactor.fix: refactor.back.fix + +## Refactor - Run refactor checks for backend +refactor.back: + $(PHP) vendor/bin/rector process --dry-run + +## Refactor - Run refactor checks for backend and fix issues +refactor.back.fix: + $(PHP) vendor/bin/rector process + +################ +# Coding style # +################ + +## Coding style - Run all coding style checks +cs: cs.back cs.front + +## Coding style - Run all coding style checks and fix issues +cs.fix: cs.back.fix cs.front.fix + +## Coding style - Check backend coding style +cs.back: + $(PHP) vendor/bin/ecs check + $(PHP) vendor/bin/twig-cs-fixer + +## Coding style - Check backend coding style and fix issues +cs.back.fix: + $(PHP) vendor/bin/ecs check --fix + $(PHP) vendor/bin/twig-cs-fixer --fix + +## Coding style - Check frontend coding style +cs.front: bin/oxfmt + bin/oxfmt --check + +## Coding style - Check frontend coding style and fix issues +cs.front.fix: bin/oxfmt + bin/oxfmt + +bin/oxfmt: + @$(call action, Downloading oxfmt...) + $(SF_CONSOLE) oxc:download:oxfmt + @$(call success, oxfmt downloaded successfully) + +########## +# Linter # +########## + +## Linter - Run all linters +lint: lint.back lint.front + +## Linter - Run all linters and fix issues +lint.fix: lint.back lint.front.fix + +## Linter - Run linters for backend +lint.back: + $(SF_CONSOLE) lint:container + $(SF_CONSOLE) lint:xliff translations + $(SF_CONSOLE) lint:yaml --parse-tags config + $(SF_CONSOLE) lint:twig templates + #$(SF_CONSOLE) doctrine:schema:validate + +## Linter - Lint front files +lint.front: bin/oxlint + bin/oxlint + +## Linter - Lint front files and fix issues +lint.front.fix: bin/oxlint + bin/oxlint --fix + +bin/oxlint: + @$(call action, Downloading oxlint...) + $(SF_CONSOLE) oxc:download:oxlint + +########### +# PHPStan # +########### + +## PHPStan - Run PHPStan +phpstan: + $(PHP) vendor/bin/phpstan analyse + +## PHPStan - Run PHPStan and update the baseline +phpstan.generate-baseline: + $(PHP) vendor/bin/phpstan analyse --generate-baseline + +######### +# Tests # +######### + +## Tests - Run all tests +test: test.back + +## Tests - Run backend tests +test.back: + $(PHP) vendor/bin/phpunit +## Tests - Run backend tests with coverage + +test.back.coverage: + $(PHP) vendor/bin/phpunit --coverage-html .cache/phpunit/coverage-html + +-include $(ROOT_DIR)/Makefile.local diff --git a/kocal/symfony-app-pack/1.0/Makefile.local b/kocal/symfony-app-pack/1.0/Makefile.local new file mode 100644 index 00000000..935396a8 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/Makefile.local @@ -0,0 +1 @@ +# Local targets that should not be committed to git diff --git a/kocal/symfony-app-pack/1.0/ecs.php b/kocal/symfony-app-pack/1.0/ecs.php new file mode 100644 index 00000000..a8f7e9c3 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/ecs.php @@ -0,0 +1,29 @@ +withParallel() + ->withCache(__DIR__ . '/tools/.cache/ecs') + ->withPaths([ + __DIR__ . '/assets', + __DIR__ . '/config', + __DIR__ . '/public', + __DIR__ . '/src', + __DIR__ . '/tests', + __DIR__ . '/tools', + ]) + ->withSkip([ + __DIR__ . '/tools/.cache', + __DIR__ . '/config/bundles.php', + __DIR__ . '/config/reference.php', + ]) + ->withPreparedSets( + psr12: true, + common: true, + strict: true, + cleanCode: true, + ) +; diff --git a/kocal/symfony-app-pack/1.0/manifest.json b/kocal/symfony-app-pack/1.0/manifest.json new file mode 100644 index 00000000..ecb86373 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/manifest.json @@ -0,0 +1,15 @@ +{ + "copy-from-recipe": { + ".github/": ".github/", + "tools/": "tools/", + ".twig-cs-fixer.php": ".twig-cs-fixer.php", + "ecs.php": "ecs.php", + "Makefile.local": "Makefile.local", + "php.ini": "php.ini", + "phpstan.dist.neon": "phpstan.dist.neon", + "rector.php": "rector.php" + }, + "gitignore": [ + "/Makefile.local" + ] +} diff --git a/kocal/symfony-app-pack/1.0/php.ini b/kocal/symfony-app-pack/1.0/php.ini new file mode 100644 index 00000000..7999e961 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/php.ini @@ -0,0 +1 @@ +memory_limit = -1 diff --git a/kocal/symfony-app-pack/1.0/phpstan.dist.neon b/kocal/symfony-app-pack/1.0/phpstan.dist.neon new file mode 100644 index 00000000..3214498f --- /dev/null +++ b/kocal/symfony-app-pack/1.0/phpstan.dist.neon @@ -0,0 +1,36 @@ +includes: + - vendor/kocal/phpstan-symfony-ux/extension.neon + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-doctrine/extension.neon + - tools/phpstan/symfony-configuration.php + +parameters: + level: 9 + paths: + - bin/ + - config/ + - public/ + - src/ + - tools/ + - tests/ + excludePaths: + - config/reference.php + - tools/.cache + + tmpDir: tools/.cache/phpstan + + symfony: + consoleApplicationLoader: tools/phpstan/console-application.php + + doctrine: + objectManagerLoader: tools/phpstan/object-manager.php + +rules: + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ClassMustBeFinalRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ClassNameMustNotEndWithComponentRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ForbiddenAttributesPropertyRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ForbiddenClassPropertyRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\MethodsVisibilityRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PostMountMethodSignatureRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PreMountMethodSignatureRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PublicPropertiesMustBeCamelCaseRule diff --git a/kocal/symfony-app-pack/1.0/rector.php b/kocal/symfony-app-pack/1.0/rector.php new file mode 100644 index 00000000..a70172c1 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/rector.php @@ -0,0 +1,37 @@ +withParallel() + ->withCache(__DIR__ . '/tools/.cache/rector') + ->withPaths([ + __DIR__ . '/config', + __DIR__ . '/public', + __DIR__ . '/src', + __DIR__ . '/tests', + __DIR__ . '/tools', + ]) + ->withPhpSets() + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + typeDeclarations: true, + privatization: true, + instanceOf: true, + earlyReturn: true, + phpunitCodeQuality: true, + doctrineCodeQuality: true, + symfonyCodeQuality: true, + ) + ->withSkip([ + __DIR__ . '/config/bundles.php', + __DIR__ . '/config/reference.php', + __DIR__ . '/tools/.cache', + ControllerMethodInjectionToConstructorRector::class, + ]) +; diff --git a/kocal/symfony-app-pack/1.0/tools/.gitignore b/kocal/symfony-app-pack/1.0/tools/.gitignore new file mode 100644 index 00000000..ceddaa37 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/.gitignore @@ -0,0 +1 @@ +.cache/ diff --git a/kocal/symfony-app-pack/1.0/tools/make/git.mk b/kocal/symfony-app-pack/1.0/tools/make/git.mk new file mode 100644 index 00000000..69b036d1 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/make/git.mk @@ -0,0 +1,30 @@ +######## +# Diff # +######## + +# Returns the list of changed files for some given extensions and some given folders. +# +# @param $1 The file extensions of changed files +# @param $2 The relative folders to parse for changed files +# +# Examples: +# +# Example #1: list PHP and Javascript files changed in the src and test folders +# +# $(call git_diff, php js, src test) + +define git_diff +$(shell \ + for ext in $(if $(strip $(1)),$(strip $(1)),"") ; \ + do \ + for dir in $(if $(strip $(2)),$(strip $(2)),"") ; \ + do \ + git --no-pager diff --name-status "$$(git merge-base HEAD origin/master)" \ + | grep "$${ext}\$$" \ + | grep "\\s$${dir}" \ + | grep -v '^D' \ + | awk '{ print $$NF }' || true ; \ + done ; \ + done \ +) +endef diff --git a/kocal/symfony-app-pack/1.0/tools/make/help.mk b/kocal/symfony-app-pack/1.0/tools/make/help.mk new file mode 100644 index 00000000..e83413bb --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/make/help.mk @@ -0,0 +1,70 @@ +######## +# Help # +######## + +.DEFAULT_GOAL := help + +HELP = \ + Usage: make [$(COLOR_INFO)command$(COLOR_RESET)] \ + $(call help_section, Help) \ + $(call help,help,This help) + +define help_section + \n\n$(COLOR_COMMENT)$(strip $(1)):$(COLOR_RESET) +endef + +define help + \n $(COLOR_INFO)$(1)$(COLOR_RESET) $(2) +endef + + +help: + @printf "\n$(HELP)" + @awk ' \ + BEGIN { \ + sectionsName[1] = "Commands" ; \ + sectionsCount = 1 ; \ + } \ + /^[-a-zA-Z0-9_.@%\/+]+:/ { \ + if (match(lastLine, /^## (.*)/)) { \ + command = substr($$1, 1, index($$1, ":") - 1) ; \ + section = substr(lastLine, RSTART + 3, index(lastLine, " - ") - 4) ; \ + if (section) { \ + message = substr(lastLine, index(lastLine, " - ") + 3, RLENGTH) ; \ + sectionIndex = 0 ; \ + for (i = 1; i <= sectionsCount; i++) { \ + if (sectionsName[i] == section) { \ + sectionIndex = i ; \ + } \ + } \ + if (!sectionIndex) { \ + sectionIndex = sectionsCount++ + 1 ; \ + sectionsName[sectionIndex] = section ; \ + } \ + } else { \ + message = substr(lastLine, RSTART + 3, RLENGTH) ; \ + sectionIndex = 1 ; \ + } \ + if (length(command) > sectionsCommandLength[sectionIndex]) { \ + sectionsCommandLength[sectionIndex] = length(command) ; \ + } \ + sectionCommandIndex = sectionsCommandCount[sectionIndex]++ + 1; \ + helpsCommand[sectionIndex, sectionCommandIndex] = command ; \ + helpsMessage[sectionIndex, sectionCommandIndex] = message ; \ + } \ + } \ + { lastLine = $$0 } \ + END { \ + for (i = 1; i <= sectionsCount; i++) { \ + if (sectionsCommandCount[i]) { \ + printf "\n\n$(COLOR_COMMENT)%s:$(COLOR_RESET)", sectionsName[i] ; \ + for (j = 1; j <= sectionsCommandCount[i]; j++) { \ + printf "\n $(COLOR_INFO)%-" sectionsCommandLength[i] "s$(COLOR_RESET) %s", helpsCommand[i, j], helpsMessage[i, j] ; \ + } \ + } \ + } \ + } \ + ' $(MAKEFILE_LIST) + @printf "\n\n" + +.PHONY: help diff --git a/kocal/symfony-app-pack/1.0/tools/make/os.mk b/kocal/symfony-app-pack/1.0/tools/make/os.mk new file mode 100644 index 00000000..dc7b4258 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/make/os.mk @@ -0,0 +1,21 @@ +###### +# Os # +###### + +# Os detection helpers. +# +# Examples: +# +# Example #1: conditions on linux +# +# echo $(if $(OS_LINUX),Running on Linux,*NOT* running on Linux) + +ifeq ($(OS),Windows_NT) +OS = windows +OS_WINDOWS = 1 +else +# See: https://make.mad-scientist.net/deferred-simple-variable-expansion/ +OS = $(eval OS := $$(shell uname -s | tr '[:upper:]' '[:lower:]'))$(OS) +OS_LINUX = $(if $(findstring linux,$(OS)),1) +OS_DARWIN = $(if $(findstring darwin,$(OS)),1) +endif diff --git a/kocal/symfony-app-pack/1.0/tools/make/text.mk b/kocal/symfony-app-pack/1.0/tools/make/text.mk new file mode 100644 index 00000000..714ab681 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/make/text.mk @@ -0,0 +1,103 @@ +########## +# Colors # +########## + +COLOR_RESET := \033[0m +COLOR_BOLD_ITALIC := \033[1;4m +COLOR_ERROR := \033[31m +COLOR_INFO := \033[32m +COLOR_WARNING := \033[33m +COLOR_COMMENT := \033[36m + +###################### +# Special Characters # +###################### + +# Usage: +# $(call message, Foo$(,) bar) = Foo, bar + +, := , + +######## +# Time # +######## + +# Usage: +# $(call time) = 11:06:20 + +define time +`date -u +%T` +endef + +########### +# Message # +########### + +# Usage: +# $(call message, Foo bar) = Foo bar +# $(call message_success, Foo bar) = (っ◕‿◕)っ Foo bar +# $(call message_warning, Foo bar) = ¯\_(ツ)_/¯ Foo bar +# $(call message_error, Foo bar) = (╯°□°)╯︵ ┻━┻ Foo bar + +define message + printf "$(COLOR_INFO)$(strip $(1))$(COLOR_RESET)\n" +endef + +define message_success + printf "$(COLOR_INFO)(っ◕‿◕)っ $(strip $(1))$(COLOR_RESET)\n" +endef + +define message_warning + printf "$(COLOR_WARNING)$(strip $(1))$(COLOR_RESET)\n" +endef + +define message_error + printf "$(COLOR_ERROR)(╯°□°)╯︵ ┻━┻ $(strip $(1))$(COLOR_RESET)\n" +endef + +########### +# Confirm # +########### + +# Usage: +# $(call confirm, Foo bar) = ༼ つ ◕_◕ ༽つ Foo bar (y/N): + +define confirm + $(if $(CONFIRM),, \ + printf "$(COLOR_INFO) ༼ つ ◕_◕ ༽つ $(COLOR_WARNING)$(strip $(1)) $(COLOR_RESET)$(COLOR_WARNING)(y/N)$(COLOR_RESET): "; \ + read CONFIRM ; if [ "$$CONFIRM" != "y" ]; then printf "\n"; exit 1; fi; \ + ) +endef + +####### +# Log # +####### + +# Usage: +# $(call log, Foo bar) = [11:06:20] [target] Foo bar +# $(call log_warning, Foo bar) = [11:06:20] [target] ¯\_(ツ)_/¯ Foo bar +# $(call log_error, Foo bar) = [11:06:20] [target] (╯°□°)╯︵ ┻━┻ Foo bar +# $(call log_and_call, echo 'Message') = [11:06:20] [target] echo 'Message' then execute the command + +define log + printf "[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] " ; $(call message, $(1)) +endef + +define log_warning + printf "[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] " ; $(call message_warning, $(1)) +endef + +define log_error + printf "[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] " ; $(call message_error, $(1)) +endef + +########## +# Action # +########## + +# Usage: +# $(call action, Foo bar) = > Foo bar (in bold) + +define action + printf "\n$(COLOR_BOLD_ITALIC)>>> $(strip $(1))$(COLOR_RESET)\n\n" +endef diff --git a/kocal/symfony-app-pack/1.0/tools/phpstan/console-application.php b/kocal/symfony-app-pack/1.0/tools/phpstan/console-application.php new file mode 100644 index 00000000..ba4e7489 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/phpstan/console-application.php @@ -0,0 +1,18 @@ +bootEnv(__DIR__ . '/../../.env'); + +// @phpstan-ignore-next-line argument.type +$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); + +return new Application($kernel); diff --git a/kocal/symfony-app-pack/1.0/tools/phpstan/object-manager.php b/kocal/symfony-app-pack/1.0/tools/phpstan/object-manager.php new file mode 100644 index 00000000..ed2b1b25 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/phpstan/object-manager.php @@ -0,0 +1,22 @@ +bootEnv(__DIR__ . '/../../.env'); + +// @phpstan-ignore-next-line argument.type +$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); +$kernel->boot(); + +/** @var EntityManager $entityManager */ +$entityManager = $kernel->getContainer()->get('doctrine')->getManager(); + +return $entityManager; diff --git a/kocal/symfony-app-pack/1.0/tools/phpstan/symfony-configuration.php b/kocal/symfony-app-pack/1.0/tools/phpstan/symfony-configuration.php new file mode 100644 index 00000000..9971f3e3 --- /dev/null +++ b/kocal/symfony-app-pack/1.0/tools/phpstan/symfony-configuration.php @@ -0,0 +1,26 @@ + [ + 'symfony' => [ + 'containerXmlPath' => $xmlContainerFile, + ], + ], +];