diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..d1f7e184 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,79 @@ +# Git files +.git +.github +.gitignore +.gitattributes + +# Documentation +*.md +docs/ +DEVELOPER_NOTES.md +ARCHITECTURE.md + +# CI/CD +.circleci + +# IDE +.vscode +.idea +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Development files +.env +.env.* +!.env.example +.env.testing + +# Dependencies (will be installed in container) +vendor/ +node_modules/ + +# Build artifacts +public/hot +public/storage +public/build/ +storage/framework/cache/* +storage/framework/sessions/* +storage/framework/views/* +storage/logs/* +bootstrap/cache/* +!storage/framework/cache/.gitkeep +!storage/framework/sessions/.gitkeep +!storage/framework/views/.gitkeep +!storage/logs/.gitkeep +!bootstrap/cache/.gitkeep + +# Test files +tests/ +phpunit.xml +.phpunit.result.cache +coverage/ +.coverage + +# Package manager files (excluding lock files needed for builds) +npm-debug.log +yarn-error.log + +# Laravel specific +Homestead.yaml +Homestead.json +/.vagrant +rr +.rr.yaml + +# Backup files +*.bak +*.backup +*.sql +*.dump + +# Temporary files +tmp/ +temp/ +*.tmp diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml index ff71cc3e..421ff41c 100644 --- a/.github/workflows/install.yml +++ b/.github/workflows/install.yml @@ -18,13 +18,26 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: '8.5' + extensions: mbstring, bcmath, pdo, mysql, dom, curl - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '24' + cache: 'npm' + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- - - name: Start database run: sudo /etc/init.d/mysql start diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 09c2ba59..8230db56 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,31 +18,34 @@ jobs: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - - - name: Login to Docker Hub + - name: Checkout code + uses: actions/checkout@v4 + + - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f + uses: docker/metadata-action@v5 with: images: liberu/boilerplate - - - # Setting up Docker Buildx with docker-container driver is required - # at the moment to be able to use a subdirectory with Git context - name: Set up Docker Buildx + # Setting up Docker Buildx with docker-container driver is required + # at the moment to be able to use a subdirectory with Git context + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build and push Docker image - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 + uses: docker/build-push-action@v6 with: - # context: "{{defaultContext}}:.docker/prod/app/" + context: . file: Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=liberu/boilerplate:buildcache + cache-to: type=registry,ref=liberu/boilerplate:buildcache,mode=max + diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 6e39fa51..02d645ae 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -22,6 +22,20 @@ jobs: - uses: shivammathur/setup-php@v2 with: php-version: '8.5' + extensions: mbstring, bcmath, pdo, mysql, dom, curl + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + - name: 'Run Phpcpd' run: | sudo composer install @@ -35,6 +49,20 @@ jobs: - uses: shivammathur/setup-php@v2 with: php-version: '8.5' + extensions: mbstring, bcmath, pdo, mysql, dom, curl + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + - name: 'Run php-insight' run: | sudo composer install @@ -47,6 +75,20 @@ jobs: - uses: shivammathur/setup-php@v2 with: php-version: '8.5' + extensions: mbstring, bcmath, pdo, mysql, dom, curl + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + - name: 'Run php-insight' run: | PHP_SC_VERSION=$(curl -s "https://api.github.com/repos/fabpot/local-php-security-checker/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/;s/^v//') diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 99e23bf6..23b10eaa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,6 +18,19 @@ jobs: with: php-version: '8.5' extensions: mbstring, bcmath, pdo, mysql, dom, curl + coverage: xdebug + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- - name: Start database run: sudo /etc/init.d/mysql start diff --git a/Dockerfile b/Dockerfile index 394dc092..7a87fef3 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,28 @@ # Accepted values: 8.3 - 8.2 ARG PHP_VERSION=8.3 -ARG COMPOSER_VERSION=latest +########################################### +# Composer dependencies stage +########################################### +FROM composer:latest AS composer-deps -ARG NODE_VERSION=20-alpine +WORKDIR /app -########################################### +# Copy composer files +COPY composer.json composer.lock ./ -FROM composer:${COMPOSER_VERSION} AS vendor +# Install composer dependencies (no autoloader yet, will optimize in final stage) +RUN composer install \ + --no-dev \ + --no-interaction \ + --no-autoloader \ + --no-ansi \ + --no-scripts \ + --prefer-dist +########################################### +# Main application stage +########################################### FROM php:${PHP_VERSION}-cli-alpine LABEL maintainer="SMortexa " @@ -39,8 +53,9 @@ RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \ ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ -RUN apk update; \ - apk upgrade; \ +# Install system dependencies and PHP extensions in one layer +RUN apk update && \ + apk upgrade && \ apk add --no-cache \ curl \ wget \ @@ -49,9 +64,8 @@ RUN apk update; \ procps \ ca-certificates \ supervisor \ - libsodium-dev \ - # Install PHP extensions - && install-php-extensions \ + libsodium-dev && \ + install-php-extensions \ bz2 \ pcntl \ mbstring \ @@ -70,9 +84,9 @@ RUN apk update; \ memcached \ igbinary \ ldap \ - swoole \ - && docker-php-source delete \ - && rm -rf /var/cache/apk/* /tmp/* /var/tmp/* + swoole && \ + docker-php-source delete && \ + rm -rf /var/cache/apk/* /tmp/* /var/tmp/* RUN arch="$(apk --print-arch)" \ && case "$arch" in \ @@ -99,48 +113,48 @@ RUN cp ${PHP_INI_DIR}/php.ini-production ${PHP_INI_DIR}/php.ini USER ${USER} -COPY --chown=${USER}:${USER} --from=vendor /usr/bin/composer /usr/bin/composer -COPY --chown=${USER}:${USER} composer.json composer.lock ./ +# Install Composer from official image +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -RUN composer install \ - --no-dev \ - --no-interaction \ - --no-autoloader \ - --no-ansi \ - --no-scripts \ - --audit +# Copy vendor from composer-deps stage for better caching +COPY --chown=${USER}:${USER} --from=composer-deps /app/vendor ./vendor -COPY --chown=${USER}:${USER} . . +# Copy composer files (needed for autoloader generation) +COPY --chown=${USER}:${USER} composer.json composer.lock ./ +# Generate optimized autoloader with vendor already in place +RUN composer dump-autoload --classmap-authoritative --no-dev && \ + composer clear-cache + +# Copy application code +COPY --chown=${USER}:${USER} . . + +# Create necessary Laravel directories RUN mkdir -p \ storage/framework/sessions \ storage/framework/views \ storage/framework/cache \ storage/framework/testing \ storage/logs \ - bootstrap/cache && chmod -R a+rw storage + bootstrap/cache && \ + chmod -R a+rw storage -COPY --chown=${USER}:${USER} .docker/supervisord.conf /etc/supervisor/ -COPY --chown=${USER}:${USER} .docker/octane/Swoole/supervisord.swoole.conf /etc/supervisor/conf.d/ -COPY --chown=${USER}:${USER} .docker/supervisord.*.conf /etc/supervisor/conf.d/ -COPY --chown=${USER}:${USER} .docker/php.ini ${PHP_INI_DIR}/conf.d/99-octane.ini -COPY --chown=${USER}:${USER} .docker/start-container /usr/local/bin/start-container +# Copy configuration files +COPY --chown=${USER}:${USER} .docker/supervisord.conf /etc/supervisor/ +COPY --chown=${USER}:${USER} .docker/octane/Swoole/supervisord.swoole.conf /etc/supervisor/conf.d/ +COPY --chown=${USER}:${USER} .docker/supervisord.*.conf /etc/supervisor/conf.d/ +COPY --chown=${USER}:${USER} .docker/php.ini ${PHP_INI_DIR}/conf.d/99-octane.ini +COPY --chown=${USER}:${USER} .docker/start-container /usr/local/bin/start-container -RUN composer install \ - --classmap-authoritative \ - --no-interaction \ - --no-ansi \ - --no-dev \ - && composer clear-cache +# Copy environment file +COPY --chown=${USER}:${USER} .env.example ./.env -COPY .env.example ./.env - -RUN chmod +x /usr/local/bin/start-container - -RUN cat .docker/utilities.sh >> ~/.bashrc +RUN chmod +x /usr/local/bin/start-container && \ + cat .docker/utilities.sh >> ~/.bashrc EXPOSE 8000 ENTRYPOINT ["start-container"] HEALTHCHECK --start-period=5s --interval=2s --timeout=5s --retries=8 CMD php artisan octane:status || exit 1 +