From a797c68d8b5d73066a93333fd770d7d35fe139e9 Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Sun, 29 Dec 2024 19:13:11 +0100 Subject: [PATCH 1/8] Add simple docker setup with easy code style --- .gitattributes | 4 +++- .gitignore | 1 + composer.json | 4 ++++ development/Dockerfile | 18 ++++++++++++++++++ development/compose.yaml | 7 +++++++ development/ecs.php | 27 +++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 development/Dockerfile create mode 100644 development/compose.yaml create mode 100644 development/ecs.php diff --git a/.gitattributes b/.gitattributes index f317bf1..7d4c034 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ -docs export-ignore \ No newline at end of file +docs export-ignore +development export-ignore +Taskfile export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/composer.json b/composer.json index 13be77b..eead4a4 100644 --- a/composer.json +++ b/composer.json @@ -3,8 +3,12 @@ "description": "User agreements made simple", "type": "symfony-bundle", "require": { + "php": "^8.1", "symfony/framework-bundle": "^6.4 || ^7.1" }, + "require-dev": { + "symplify/easy-coding-standard": "^12.5" + }, "license": "MIT", "autoload": { "psr-4": { diff --git a/development/Dockerfile b/development/Dockerfile new file mode 100644 index 0000000..3f35502 --- /dev/null +++ b/development/Dockerfile @@ -0,0 +1,18 @@ +FROM php:8.2-alpine3.21 + +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer +COPY --chown=php:nginx ./ /www + +RUN apk add --no-cache \ + bash \ + git \ + zip \ + unzip + +WORKDIR /www + +RUN set -eux; \ + COMPOSER_MEMORY_LIMIT=2G composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress; \ + composer clear-cache + +CMD ["sleep", "infinity"] diff --git a/development/compose.yaml b/development/compose.yaml new file mode 100644 index 0000000..f49db6c --- /dev/null +++ b/development/compose.yaml @@ -0,0 +1,7 @@ +services: + php: + build: + context: ../. + dockerfile: development/Dockerfile + volumes: + - ../.:/www \ No newline at end of file diff --git a/development/ecs.php b/development/ecs.php new file mode 100644 index 0000000..13ad1c8 --- /dev/null +++ b/development/ecs.php @@ -0,0 +1,27 @@ +withPaths([ + __DIR__ . '/../src', + ]) + + // add a single rule + ->withRules([ + NoUnusedImportsFixer::class, + ]) + + // add sets - group of rules + ->withPreparedSets( + arrays: true, + namespaces: true, + spaces: true, + docblocks: true, + comments: true, + psr12: true + ); From 0084f1bba1b5db6875a7e7e6cd7cfa9f75b2f469 Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Sun, 29 Dec 2024 19:16:07 +0100 Subject: [PATCH 2/8] Ran easy code style with --fix --- src/Entity/Traits/UserAgreementTrait.php | 6 +-- src/Entity/UserAgreement.php | 6 +-- .../DoctrineMetadataListener.php | 5 +- src/Form/AgreementFormType.php | 8 +-- src/Repository/UserAgreementRepository.php | 2 +- src/Service/AgreementHandlingService.php | 18 ++++--- src/Service/AgreementService.php | 8 +-- src/UserAgreementsBundle.php | 51 +++++++++---------- 8 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/Entity/Traits/UserAgreementTrait.php b/src/Entity/Traits/UserAgreementTrait.php index 2470545..9f07dc5 100644 --- a/src/Entity/Traits/UserAgreementTrait.php +++ b/src/Entity/Traits/UserAgreementTrait.php @@ -2,9 +2,9 @@ namespace RobertvanLienden\UserAgreements\Entity\Traits; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use RobertvanLienden\UserAgreements\Entity\UserAgreement; trait UserAgreementTrait @@ -24,7 +24,7 @@ public function getUserAgreements(): Collection public function addUserAgreement(UserAgreement $userAgreement): self { - if (!$this->userAgreements->contains($userAgreement)) { + if (! $this->userAgreements->contains($userAgreement)) { $this->userAgreements[] = $userAgreement; $userAgreement->setUser($this); } @@ -40,4 +40,4 @@ public function removeUserAgreement(UserAgreement $userAgreement): self return $this; } -} \ No newline at end of file +} diff --git a/src/Entity/UserAgreement.php b/src/Entity/UserAgreement.php index 79cf993..226266c 100644 --- a/src/Entity/UserAgreement.php +++ b/src/Entity/UserAgreement.php @@ -7,7 +7,8 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UserAgreementRepository::class)] -class UserAgreement { +class UserAgreement +{ #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] @@ -26,7 +27,6 @@ class UserAgreement { #[ORM\JoinColumn(name: 'user_id', nullable: true)] private ?UserInterface $user = null; - public function getId(): ?int { return $this->id; @@ -77,4 +77,4 @@ public function setUser(?UserInterface $user): self $this->user = $user; return $this; } -} \ No newline at end of file +} diff --git a/src/EventListener/DoctrineMetadataListener.php b/src/EventListener/DoctrineMetadataListener.php index df10b29..8e9a227 100644 --- a/src/EventListener/DoctrineMetadataListener.php +++ b/src/EventListener/DoctrineMetadataListener.php @@ -8,8 +8,9 @@ class DoctrineMetadataListener implements EventSubscriber { - public function __construct(private string $userEntityClass) - { + public function __construct( + private string $userEntityClass + ) { } public function getSubscribedEvents() diff --git a/src/Form/AgreementFormType.php b/src/Form/AgreementFormType.php index 09f9719..88fdc4a 100644 --- a/src/Form/AgreementFormType.php +++ b/src/Form/AgreementFormType.php @@ -4,15 +4,17 @@ use RobertvanLienden\UserAgreements\Service\AgreementService; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class AgreementFormType extends AbstractType { - public function __construct(private AgreementService $agreementService, private UrlGeneratorInterface $urlGenerator) - { + public function __construct( + private AgreementService $agreementService, + private UrlGeneratorInterface $urlGenerator + ) { } public function buildForm(FormBuilderInterface $builder, array $options) diff --git a/src/Repository/UserAgreementRepository.php b/src/Repository/UserAgreementRepository.php index 78ee2f7..baa95e2 100644 --- a/src/Repository/UserAgreementRepository.php +++ b/src/Repository/UserAgreementRepository.php @@ -20,4 +20,4 @@ public function __construct(ManagerRegistry $registry) { parent::__construct($registry, UserAgreement::class); } -} \ No newline at end of file +} diff --git a/src/Service/AgreementHandlingService.php b/src/Service/AgreementHandlingService.php index 7b8b913..91d8c08 100644 --- a/src/Service/AgreementHandlingService.php +++ b/src/Service/AgreementHandlingService.php @@ -9,8 +9,10 @@ class AgreementHandlingService { - public function __construct(private EntityManagerInterface $entityManager, private AgreementService $agreementService) - { + public function __construct( + private EntityManagerInterface $entityManager, + private AgreementService $agreementService + ) { } /** @@ -18,10 +20,12 @@ public function __construct(private EntityManagerInterface $entityManager, priva */ public function handleAgreementsFromFormType(array $agreements, UserInterface $user, bool $flushEntities = false): void { - if (!in_array(UserAgreementTrait::class, class_uses(get_class($user)))) { + if (! in_array(UserAgreementTrait::class, class_uses(get_class($user)))) { throw new \InvalidArgumentException( - sprintf('User does not have the %s. This is needed to handle agreements', - UserAgreementTrait::class) + sprintf( + 'User does not have the %s. This is needed to handle agreements', + UserAgreementTrait::class + ) ); } @@ -51,7 +55,7 @@ private function normalizeAgreementsLabels(array $agreements): array private function createUserAgreements(array $agreements, UserInterface $user): void { foreach ($agreements as $key => $value) { - if (!$value) { + if (! $value) { continue; } @@ -70,4 +74,4 @@ private function createUserAgreements(array $agreements, UserInterface $user): v $this->entityManager->persist($agreement); } } -} \ No newline at end of file +} diff --git a/src/Service/AgreementService.php b/src/Service/AgreementService.php index 7c44580..2e89e3e 100644 --- a/src/Service/AgreementService.php +++ b/src/Service/AgreementService.php @@ -6,8 +6,10 @@ class AgreementService { - public function __construct(ContainerBagInterface $containerBag, private array $agreements = []) - { + public function __construct( + ContainerBagInterface $containerBag, + private array $agreements = [] + ) { $this->agreements = $containerBag->get('user_agreements')['agreements']; } @@ -22,4 +24,4 @@ public function findAgreement(string $label): ?array return $this->agreements[$arrayKey] ?? null; } -} \ No newline at end of file +} diff --git a/src/UserAgreementsBundle.php b/src/UserAgreementsBundle.php index 64ed9b1..e2f6c27 100644 --- a/src/UserAgreementsBundle.php +++ b/src/UserAgreementsBundle.php @@ -2,7 +2,6 @@ namespace RobertvanLienden\UserAgreements; -use RobertvanLienden\UserAgreements\DependencyInjection\DoctrineMappingPass; use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -21,30 +20,30 @@ public function configure(DefinitionConfigurator $definition): void { // Configure agreements $definition->rootNode() - ->children() - ->scalarNode('user_entity') - ->defaultValue('App\Entity\User') - ->end() - ->arrayNode('agreements') - ->arrayPrototype() - ->children() - ->scalarNode('label') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('route_name') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->booleanNode('required') - ->isRequired() - ->end() - ->scalarNode('version') - ->defaultValue('1.0') - ->end() - ->end() - ->end() - ->end() + ->children() + ->scalarNode('user_entity') + ->defaultValue('App\Entity\User') + ->end() + ->arrayNode('agreements') + ->arrayPrototype() + ->children() + ->scalarNode('label') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('route_name') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->booleanNode('required') + ->isRequired() + ->end() + ->scalarNode('version') + ->defaultValue('1.0') + ->end() + ->end() + ->end() + ->end() ->end(); } -} \ No newline at end of file +} From 060324669888c344df33aeb43ca44b8d091b5f88 Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 17:54:55 +0100 Subject: [PATCH 3/8] Ignore composer.lock --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5657f6e..88e99d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -vendor \ No newline at end of file +vendor +composer.lock \ No newline at end of file From 07ffc314d6cc869741254e993bf601020916e646 Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 17:55:48 +0100 Subject: [PATCH 4/8] Add basic Taskfile --- Taskfile | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100755 Taskfile diff --git a/Taskfile b/Taskfile new file mode 100755 index 0000000..da6b4ce --- /dev/null +++ b/Taskfile @@ -0,0 +1,88 @@ +#!/bin/bash +# ========================================================= +# Taskfile gives you a set of quick tasks for your project +# More info: https://github.com/Enrise/Taskfile +# ========================================================= + +function banner { + echo -e "${BLUE}\n"\ + "██╗ ██╗███████╗███████╗██████╗ █████╗ ██████╗ ██████╗ ███████╗███████╗███╗ ███╗███████╗███╗ ██╗████████╗███████╗\n"\ + "██║ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝ ██╔══██╗██╔════╝██╔════╝████╗ ████║██╔════╝████╗ ██║╚══██╔══╝██╔════╝\n"\ + "██║ ██║███████╗█████╗ ██████╔╝███████║██║ ███╗██████╔╝█████╗ █████╗ ██╔████╔██║█████╗ ██╔██╗ ██║ ██║ ███████╗\n"\ + "██║ ██║╚════██║██╔══╝ ██╔══██╗██╔══██║██║ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║\n"\ + "╚██████╔╝███████║███████╗██║ ██║██║ ██║╚██████╔╝██║ ██║███████╗███████╗██║ ╚═╝ ██║███████╗██║ ╚████║ ██║ ███████║\n"\ + " ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝${RESET}" +} + +# ========================================================= +## Project +# ========================================================= + +function task:start { ## Start the project in development mode + title "Run development environment" + dockercompose up -d +} + +function task:build { ## Build docker compose file + title "Build docker compose" + dockercompose build +} + +function task:shell { ## Shell into PHP container + dockercompose exec php bash +} + +# ========================================================= +## Tests +# ========================================================= +function task:codestyle { ## Run codestyle test + dockercompose-exec vendor/bin/ecs --config=development/ecs.php +} + +# ========================================================= +## Internal functions +# ========================================================= + +function dockercompose { + docker compose --file ./development/compose.yaml "$@" +} + +function dockercompose-exec { + dockercompose exec php "$@" +} + +# ========================================================= +## Taskfile +# ========================================================= + +set -eo pipefail + +BLUE=$(printf '\033[36m') +YELLOW=$(printf '\033[33m') +RED=$(printf '\033[31m') +GREEN=$(printf '\033[32m') +RESET=$(printf '\033[0m') + +# Define global variables here + +function title { + echo -e "\n${BLUE}=>${RESET} $1\n" +} + +function task:help { ## Show all available tasks + title "Available tasks" + awk 'BEGIN {FS = " { [#][#][ ]?"} /^([a-zA-Z_-]*:?.*)(\{ )?[#][#][ ]?/ \ + {printf "\033[33m%-34s\033[0m %s\n", $1, $2}' $0 |\ + sed -E "s/[#]{2,}[ ]*/${RESET}/g" |\ + sed -E "s/function task:*/ /g" + echo -e "\n${BLUE}Usage:${RESET} $0 ${YELLOW}${RESET} " +} + +banner +if [[ ! "$(declare -F task:${@-help})" ]]; then + title "Task not found" + echo -e "Task ${YELLOW}$1${RESET} doesn't exist." + task:help + exit 1 +fi +task:${@-help} From 7bd25b1deb001c55227f17276127923938f69f7e Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 18:35:29 +0100 Subject: [PATCH 5/8] Try to add CI for codestyle --- .github/workflows/build.yaml | 31 +++++++++++++++++++++++++++++++ .github/workflows/codestyle.yaml | 29 +++++++++++++++++++++++++++++ development/Dockerfile | 2 +- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/codestyle.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..70dadd7 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,31 @@ +name: Build Docker Image + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build Docker image + run: | + docker build -f development/Dockerfile -t php-ci . + + - name: Save Docker image as an artifact + uses: actions/upload-artifact@v3 + with: + name: docker-image + path: | + $(docker save php-ci | gzip > image.tar.gz) diff --git a/.github/workflows/codestyle.yaml b/.github/workflows/codestyle.yaml new file mode 100644 index 0000000..d1a19be --- /dev/null +++ b/.github/workflows/codestyle.yaml @@ -0,0 +1,29 @@ +name: Run Code Style Tests + +on: + workflow_run: + workflows: ["Build Docker Image"] + types: + - completed + +jobs: + codestyle: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Download Docker image artifact + uses: actions/download-artifact@v3 + with: + name: docker-image + path: ./image.tar.gz + + - name: Load Docker image + run: | + docker load < ./image.tar.gz + + - name: Run codestyle tests + run: | + docker run --rm php-ci ./Taskfile codestyle \ No newline at end of file diff --git a/development/Dockerfile b/development/Dockerfile index 3f35502..369772d 100644 --- a/development/Dockerfile +++ b/development/Dockerfile @@ -12,7 +12,7 @@ RUN apk add --no-cache \ WORKDIR /www RUN set -eux; \ - COMPOSER_MEMORY_LIMIT=2G composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress; \ + COMPOSER_MEMORY_LIMIT=2G composer install --prefer-dist --no-autoloader --no-scripts --no-progress; \ composer clear-cache CMD ["sleep", "infinity"] From 382c0b2c2d072f516f83331c4071a4eff0a1c2fc Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 18:39:01 +0100 Subject: [PATCH 6/8] Try to run codestyle test in pipeline --- .github/workflows/codestyle.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/codestyle.yaml b/.github/workflows/codestyle.yaml index d1a19be..516ffb8 100644 --- a/.github/workflows/codestyle.yaml +++ b/.github/workflows/codestyle.yaml @@ -1,6 +1,12 @@ name: Run Code Style Tests on: + push: + branches: + - main + pull_request: + branches: + - main workflow_run: workflows: ["Build Docker Image"] types: From 5dfd0c406ac830aacedda7dc0f4786e696e55e74 Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 18:42:14 +0100 Subject: [PATCH 7/8] Try to do build and codestyle test in 1 workflow --- .github/workflows/codestyle.yaml | 35 ------------------- .../workflows/{build.yaml => workflow.yaml} | 11 +++--- 2 files changed, 4 insertions(+), 42 deletions(-) delete mode 100644 .github/workflows/codestyle.yaml rename .github/workflows/{build.yaml => workflow.yaml} (63%) diff --git a/.github/workflows/codestyle.yaml b/.github/workflows/codestyle.yaml deleted file mode 100644 index 516ffb8..0000000 --- a/.github/workflows/codestyle.yaml +++ /dev/null @@ -1,35 +0,0 @@ -name: Run Code Style Tests - -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_run: - workflows: ["Build Docker Image"] - types: - - completed - -jobs: - codestyle: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v3 - - - name: Download Docker image artifact - uses: actions/download-artifact@v3 - with: - name: docker-image - path: ./image.tar.gz - - - name: Load Docker image - run: | - docker load < ./image.tar.gz - - - name: Run codestyle tests - run: | - docker run --rm php-ci ./Taskfile codestyle \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/workflow.yaml similarity index 63% rename from .github/workflows/build.yaml rename to .github/workflows/workflow.yaml index 70dadd7..b868de3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/workflow.yaml @@ -1,4 +1,4 @@ -name: Build Docker Image +name: Build Docker Image and run Codestyle tests on: push: @@ -23,9 +23,6 @@ jobs: run: | docker build -f development/Dockerfile -t php-ci . - - name: Save Docker image as an artifact - uses: actions/upload-artifact@v3 - with: - name: docker-image - path: | - $(docker save php-ci | gzip > image.tar.gz) + - name: Run codestyle tests + run: | + docker run --rm php-ci ./Taskfile codestyle \ No newline at end of file From e7f54d88b663df496a3136c42b2cf5393999399f Mon Sep 17 00:00:00 2001 From: Robert van Lienden Date: Mon, 30 Dec 2024 18:45:32 +0100 Subject: [PATCH 8/8] Run ECS directly with command --- .github/workflows/workflow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index b868de3..226394c 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -25,4 +25,4 @@ jobs: - name: Run codestyle tests run: | - docker run --rm php-ci ./Taskfile codestyle \ No newline at end of file + docker run --rm php-ci vendor/bin/ecs --config=development/ecs.php \ No newline at end of file