-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Add Drupal testing workflow and Docker build trigger #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| name: Test Drupal Installation | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| jobs: | ||
| test-drupal: | ||
| name: Test on ${{ matrix.variant }} (PHP ${{ matrix.php_version }}) | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| php_version: ["8.4", "8.5"] | ||
| variant: ["apache-trixie", "fpm-alpine", "frankenphp-trixie"] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Build Docker image | ||
| run: | | ||
| docker build \ | ||
| --build-arg PHP_VERSION=${{ matrix.php_version }} \ | ||
| -t drupal-test:${{ matrix.php_version }}-${{ matrix.variant }} \ | ||
| ./php8/${{ matrix.variant }} | ||
|
|
||
| - name: Create test directory structure | ||
| run: | | ||
| mkdir -p drupal-root | ||
| mkdir -p test-results | ||
|
|
||
| - name: Download Drupal | ||
| run: | | ||
| composer create-project drupal/recommended-project drupal-root --no-interaction --no-dev | ||
| cd drupal-root | ||
| composer require drush/drush --no-interaction | ||
|
|
||
| - name: Set up environment variables | ||
| run: | | ||
| echo "PHP_VERSION=${{ matrix.php_version }}" >> $GITHUB_ENV | ||
| echo "VARIANT=${{ matrix.variant }}" >> $GITHUB_ENV | ||
| if [ "${{ matrix.variant }}" = "frankenphp-trixie" ]; then | ||
| echo "WEB_ROOT=/app" >> $GITHUB_ENV | ||
| else | ||
| echo "WEB_ROOT=/var/www/html" >> $GITHUB_ENV | ||
| fi | ||
| if [ "${{ matrix.variant }}" = "fpm-alpine" ]; then | ||
| echo "COMPOSE_FILE=tests/docker-compose.fpm.yml" >> $GITHUB_ENV | ||
| else | ||
| echo "COMPOSE_FILE=tests/docker-compose.yml" >> $GITHUB_ENV | ||
| fi | ||
| echo "CONTAINER_NAME=drupal" >> $GITHUB_ENV | ||
|
|
||
| - name: Start Docker containers | ||
| run: | | ||
| docker compose up -d | ||
| sleep 10 | ||
| docker compose ps | ||
|
|
||
| - name: Install Drupal | ||
| run: | | ||
| chmod +x tests/install-drupal.sh | ||
| # The script uses 'docker compose exec -T drupal', which matches our service name 'drupal' | ||
| ./tests/install-drupal.sh ${{ matrix.variant }} "11.x" | ||
|
|
||
| - name: Run Drupal verification tests | ||
| run: | | ||
| chmod +x tests/verify-drupal.sh | ||
| ./tests/verify-drupal.sh ${{ matrix.variant }} | ||
|
|
||
| - name: Capture logs | ||
| if: always() | ||
| run: | | ||
| echo "=== Docker Compose Logs ===" | ||
| docker compose logs | ||
| echo "=== Container Status ===" | ||
| docker compose ps | ||
| docker compose logs > test-results/docker-logs-${{ matrix.variant }}.txt | ||
|
|
||
| - name: Upload test results | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-results-${{ matrix.php_version }}-${{ matrix.variant }} | ||
| path: test-results/ | ||
| if-no-files-found: ignore | ||
|
|
||
| - name: Clean up | ||
| if: always() | ||
| run: docker compose down -v |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| services: | ||
| drupal: | ||
| image: drupal-test:${PHP_VERSION}-${VARIANT} | ||
| container_name: drupal | ||
| volumes: | ||
| - ../drupal-root:/var/www/html | ||
| nginx: | ||
| image: nginx:alpine | ||
| container_name: nginx | ||
| ports: | ||
| - "8080:80" | ||
| volumes: | ||
| - ../drupal-root:/var/www/html | ||
| - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro | ||
| depends_on: | ||
| - drupal |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| services: | ||
| drupal: | ||
| image: drupal-test:${PHP_VERSION}-${VARIANT} | ||
| container_name: drupal | ||
| volumes: | ||
| - ../drupal-root:${WEB_ROOT} | ||
| ports: | ||
| - "8080:80" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| #!/bin/bash | ||
| set -e | ||
|
|
||
| VARIANT=$1 | ||
| DRUPAL_VERSION=$2 | ||
|
|
||
| echo "====================================" | ||
| echo "Installing Drupal ${DRUPAL_VERSION} on ${VARIANT}" | ||
| echo "====================================" | ||
|
|
||
| # Use service name instead of container name | ||
| SERVICE="drupal" | ||
|
|
||
| # Set the web root path based on variant | ||
| if [[ "$VARIANT" == *"frankenphp"* ]]; then | ||
| WEBROOT="/app" | ||
| else | ||
| WEBROOT="/var/www/html" | ||
| fi | ||
|
|
||
| # Wait for the container to be fully ready with health checks | ||
| echo "Waiting for container to be ready..." | ||
| for i in {1..12}; do | ||
| if docker compose exec -T $SERVICE sh -c 'exit 0' 2>/dev/null; then | ||
| echo "Container is ready!" | ||
| break | ||
| fi | ||
| if [ $i -eq 12 ]; then | ||
| echo "Container failed to become ready after 60 seconds" | ||
| docker compose ps | ||
| docker compose logs | ||
| exit 1 | ||
| fi | ||
| echo "Waiting for container... ($i/12)" | ||
| sleep 5 | ||
| done | ||
|
|
||
| # Check if Drupal is already installed | ||
| INSTALLED=$(docker compose exec -T $SERVICE sh -c "if [ -f ${WEBROOT}/web/sites/default/settings.php ] && grep -q 'database' ${WEBROOT}/web/sites/default/settings.php 2>/dev/null; then echo 'yes'; else echo 'no'; fi" || echo "no") | ||
|
|
||
| if [ "$INSTALLED" = "yes" ]; then | ||
| echo "Drupal appears to be already installed. Skipping installation." | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Set proper permissions | ||
| echo "Setting up permissions..." | ||
| docker compose exec -T $SERVICE sh -c "mkdir -p ${WEBROOT}/web/sites/default/files && chmod -R 777 ${WEBROOT}/web/sites/default/files" | ||
| docker compose exec -T $SERVICE sh -c "chmod 777 ${WEBROOT}/web/sites/default" | ||
|
|
||
| # Install Drupal using drush with SQLite database file | ||
| echo "Installing Drupal using drush with SQLite..." | ||
| docker compose exec -T $SERVICE sh -c "cd ${WEBROOT} && vendor/bin/drush site:install minimal \ | ||
| --db-url="sqlite://localhost/sites/default/files/.ht.sqlite" \ | ||
| --site-name="Drupal Test Site" \ | ||
| --account-name=admin \ | ||
| --account-pass=admin \ | ||
| --yes \ | ||
| --no-interaction" | ||
|
Comment on lines
+53
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Nested double quotes break the The inner double quotes on lines 54–55 ( Without Shellcheck (SC2140) flagged this same issue. Proposed fix — use single quotes for inner values docker compose exec -T $SERVICE sh -c "cd ${WEBROOT} && vendor/bin/drush site:install minimal \
- --db-url="sqlite://localhost/sites/default/files/.ht.sqlite" \
- --site-name="Drupal Test Site" \
+ --db-url='sqlite://localhost/sites/default/files/.ht.sqlite' \
+ --site-name='Drupal Test Site' \
--account-name=admin \
--account-pass=admin \
--yes \
--no-interaction"🧰 Tools🪛 Shellcheck (0.11.0)[warning] 54-54: Word is of the form "A"B"C" (B indicated). Did you mean "ABC" or "A"B"C"? (SC2140) 🤖 Prompt for AI Agents |
||
|
|
||
| # Verify installation | ||
| echo "Verifying Drupal installation..." | ||
| DRUSH_STATUS=$(docker compose exec -T $SERVICE sh -c "cd ${WEBROOT} && vendor/bin/drush status --format=json" || echo "{}") | ||
|
|
||
| echo "Drush status output:" | ||
| echo "$DRUSH_STATUS" | ||
|
|
||
| # Check if bootstrap was successful | ||
| if echo "$DRUSH_STATUS" | grep -q "bootstrap"; then | ||
| echo "✓ Drupal installation completed successfully" | ||
| else | ||
| echo "✗ Drupal installation may have issues" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Set permissions back to safer values but keep files directory writable | ||
| echo "Securing permissions..." | ||
| # sites/default should not be writable by web server (755) | ||
| docker compose exec -T $SERVICE sh -c "chmod 755 ${WEBROOT}/web/sites/default" | ||
| # Keep files directory fully writable (777) for testing - SQLite needs directory write access | ||
| docker compose exec -T $SERVICE sh -c "chmod -R 777 ${WEBROOT}/web/sites/default/files" | ||
|
|
||
| echo "====================================" | ||
| echo "Drupal installation complete" | ||
| echo "Admin user: admin" | ||
| echo "Admin pass: admin" | ||
| echo "====================================" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| server { | ||
| listen 80; | ||
| server_name localhost; | ||
| root /var/www/html/web; | ||
|
|
||
| index index.php index.html index.htm; | ||
|
|
||
| # Logging | ||
| access_log /var/log/nginx/drupal_access.log; | ||
| error_log /var/log/nginx/drupal_error.log; | ||
|
|
||
| # Drupal specific configurations | ||
| location = /favicon.ico { | ||
| log_not_found off; | ||
| access_log off; | ||
| } | ||
|
|
||
| location = /robots.txt { | ||
| allow all; | ||
| log_not_found off; | ||
| access_log off; | ||
| } | ||
|
|
||
| # Very rarely should these ever be accessed outside of your lan | ||
| location ~* \.(txt|log)$ { | ||
| deny all; | ||
| } | ||
|
|
||
| location ~ \..*/.*\.php$ { | ||
| return 403; | ||
| } | ||
|
|
||
| location ~ ^/sites/.*/private/ { | ||
| return 403; | ||
| } | ||
|
|
||
| # Block access to scripts in site files directory | ||
| location ~ ^/sites/[^/]+/files/.*\.php$ { | ||
| deny all; | ||
| } | ||
|
|
||
| # Allow "Well-Known URIs" as per RFC 5785 | ||
| location ~* ^/.well-known/ { | ||
| allow all; | ||
| } | ||
|
|
||
| # Block access to "hidden" files and directories whose names begin with a | ||
| # period. This includes directories used by version control systems such | ||
| # as Subversion or Git to store control files. | ||
| location ~ (^|/)\. { | ||
| return 403; | ||
| } | ||
|
|
||
| location / { | ||
| # try_files $uri @rewrite; # For Drupal <= 6 | ||
| try_files $uri /index.php?$query_string; # For Drupal >= 7 | ||
| } | ||
|
|
||
| location @rewrite { | ||
| rewrite ^/(.*)$ /index.php?q=$1; | ||
| } | ||
|
|
||
| # Don't allow direct access to PHP files in the vendor directory. | ||
| location ~ /vendor/.*\.php$ { | ||
| deny all; | ||
| return 404; | ||
| } | ||
|
|
||
| # Protect files and directories from prying eyes. | ||
| location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { | ||
| deny all; | ||
| return 404; | ||
| } | ||
|
|
||
| location ~ '\.php$|^/update.php' { | ||
| fastcgi_split_path_info ^(.+?\.php)(|/.*)$; | ||
|
|
||
| # Ensure the php file exists. Mitigates CVE-2019-11043 | ||
| try_files $fastcgi_script_name =404; | ||
|
|
||
| # Block httpoxy attacks. See https://httpoxy.org/. | ||
| fastcgi_param HTTP_PROXY ""; | ||
|
|
||
| fastcgi_pass drupal:9000; | ||
| fastcgi_index index.php; | ||
|
|
||
| include fastcgi_params; | ||
|
|
||
| # SCRIPT_FILENAME parameter is used for PHP FPM determining | ||
| # the script name. If it is not set in fastcgi_params file, | ||
| # i.e. /etc/nginx/fastcgi_params or in the parent contexts, | ||
| # please comment off following line: | ||
| fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||
| fastcgi_param PATH_INFO $fastcgi_path_info; | ||
| fastcgi_param QUERY_STRING $query_string; | ||
|
|
||
| fastcgi_intercept_errors on; | ||
|
|
||
| # PHP 7 socket | ||
| # fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; | ||
|
|
||
| # PHP 7 TCP | ||
| # fastcgi_pass 127.0.0.1:9000; | ||
|
|
||
| fastcgi_buffer_size 128k; | ||
| fastcgi_buffers 4 256k; | ||
| fastcgi_busy_buffers_size 256k; | ||
| fastcgi_temp_file_write_size 256k; | ||
| fastcgi_read_timeout 240; | ||
| } | ||
|
|
||
| # Fighting with Styles? This little gem is amazing. | ||
| location ~ ^/sites/.*/files/styles/ { | ||
| try_files $uri @rewrite; | ||
| } | ||
|
|
||
| # Handle private files through Drupal. Private file's path can come | ||
| # with a language prefix. | ||
| location ~ ^(/[a-z\-]+)?/system/files/ { | ||
| try_files $uri /index.php?$query_string; | ||
| } | ||
|
|
||
| # Enforce clean URLs | ||
| # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page | ||
| # Could be done with 301 for permanent or other redirect codes. | ||
| if ($request_uri ~* "^(.*/)index\.php/(.*)") { | ||
| return 307 $1$2; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DRUPAL_VERSIONparameter is accepted but never used.$2is assigned toDRUPAL_VERSIONon line 5 and echoed on line 8, but it's never passed to anydrushorcomposercommand. The caller passes"11.x"from the workflow (line 66 oftest-drupal.yml), which has no effect.Either remove the parameter or use it to pin the Drupal version during installation.
🤖 Prompt for AI Agents