commit 425b396c34221cf7ffbfe84c9d657d31581c0ee0 Author: Autonomic Cooperative <> Date: Thu Oct 9 14:15:29 2025 +0000 Initial commit diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..873b86b --- /dev/null +++ b/.drone.yml @@ -0,0 +1,33 @@ +--- +kind: pipeline +name: deploy main branch to live site +steps: + - name: php syntax check + image: php:8.3.7-cli + commands: + - for f in $(find /drone -name '*.php'); do php -l "f"; done + # If a custom block is in use, uncomment this (and make sure package.json + # includes `scripts.build`, and change the `depends_on` below + # - name: compile custom block + # image: node:18.18.2 + # commands: + # - npm install + # - npm run build + # depends_on: + # - php syntax check + - name: docker cp deploy + image: git.coopcloud.tech/coop-cloud/docker-cp-deploy:latest + settings: + host: server.example.com + service: qicn_site + source: wp-content/themes/qicn-site + exec_pre: rm -rf /var/www/html/wp-content/themes/qicn-site/* + exec: composer install + dest: /var/www/html/ + deploy_key: + from_secret: drone_ssh_server.example.com + depends_on: + - php syntax check + when: + branch: + - main diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..c664405 --- /dev/null +++ b/.env.sample @@ -0,0 +1,41 @@ +############################################################################## +# REQUIRED SETTINGS (you will need these) # +############################################################################## + +# What username should `set_local_password` operate on? +USERNAME=admin + +############################################################################## +# COMMON SETTINGS (you may need these) # +############################################################################## + +# If you don't have docker-compose, but do have newer docker, uncomment this +#DOCKER_COMPOSE=docker compose + +# Uncomment the following line if you need `sudo` to run Docker commands +#DOCKER_SUDO=1 + +# Wordpress debugging +WORDPRESS_DEBUG=1 + +############################################################################## +# RARE SETTINGS (you probably won't need these) # +############################################################################## + +# TODO: insert template "connect to a remote database" settings here + +############################################################################## +# INFINITE NERD DEPTH SETTINGS (if you're changing these, good luck!) # +############################################################################## + +# Docker container names, probably just needs to be set once per project +PROJECT_NAME=qicn_site + +# Site URL, also just needs to be set once per project +SITE_URL=qicn_site.tld + +# Multi-site config +#WORDPRESS_CONFIG_EXTRA="define('MULTISITE', true); define('SUBDOMAIN_INSTALL', true); define('DOMAIN_CURRENT_SITE', 'frms.localhost'); define('PATH_CURRENT_SITE', '/'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); define('SUNRISE', true);" + +# Use composer for plugin installation +#USE_COMPOSER=1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6be32ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +/.env + +/wp-content/** +# Add an exception here for any custom plugins or themes to be included, e.g. +#!/wp-content/themes/qicn_site + +/data/** +!/data/.gitkeep + +.vscode/ +**.tar.gz +**.sql +**.zip diff --git a/README.md b/README.md new file mode 100644 index 0000000..a73f54a --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +A template for Autonomic Wordpress projects, including local set-up, and auto-deployment. + +# Usage +1. Make a new repository, using this as a template +2. Remove this notice from `README.md` (everything until the `---`) +3. Create and deploy a Co-op Cloud Wordpress app +4. Edit `.env.sample` to set `SITE_URL` (and customise `PROJECT_NAME`, if + needed) + - Change USERNAME to whatever the wordpress admin username is / should be + - Set SITE_URL to the live site URL + - Set PROJECT_NAME to some identifier for the project +5. Make sure `.drone.yml` has the right settings for the server you'd like to + deploy + - Change host to the FQDN of the host, likely smol-wp.autonomic.zone + - Set service to the docker service name, usually _app so like display_distribute_com_app + - Update source and exec_pre to the path to the theme + - Comment exec: composer install if composer isn't in use + - Set `deploy_key: from_secret:` to the secret name of the SSH key to access the server. this requires logging into drone as autonomic admin, then checking "organisation secrets" on the repo settings page of any repo in the same org. or you can use drone CLI and do drone orgsecret ls +6. Add any custom plugins / themes to `wp-content` + - Copying / moving files into the repo in wp-content, and possibly / probably excluding them from .gitignore +7. "Activate" this repository in Drone + - e.g. click "activate repository" here https://drone.autonomic.zone/autonomic-cooperative/display-distribute/settings +8. Commit to the repo to test and monitor the drone interface to troubleshoot + +--- + +# qicn-site + +_Wordpress local set-up and custom theme/plugins_ + +## Local development + +### Initial set-up + +Install Docker (and, if your Docker version doesn't include `docker compose`, +the separate `docker-compose` programme). + +Check out the code: + +``` +git clone ssh://git@git.autonomic.zone:2222/autonomic-cooperative/qicn-site.git +cd qicn-site +``` + +Copy the default environment file into place + +``` +cp .env.sample .env +``` + +Edit `.env` as needed for your local config; read the descriptions for +`DOCKER_SUDO` and `DOCKER_COMPOSE`, and set them if you need to. + +Then, download and start the Docker images: + +``` +make up # 💄 +``` + +Download uploaded media (beware possibly-large filesize) and plugins from the live site: + +``` +make uploads_pull +make plugins_pull +``` + +Then fetch and load the database: + +``` +make db_pull set_local_password +``` + +If this process is interrupted for any reason but the database was downloaded in +full, you can skip the dump/download process and just load the database and set +the URL with: + +``` +make db_load fix_url +``` + +Lastly, install any parent themes in use on the site: +``` +make theme_pull +``` + +The site should now be available: + +- **wordpress**: http://qicn-site.localhost/ +- **mailhog**: http://qicn-site.localhost:8025 + +### Updating your local version + +Run `git pull` frequently. + +Refresh from the live site as often as you can: + +```sh +make plugins_pull theme_pull db_pull set_local_password +``` + +### Running WPCLI commands + +The `make wp` shortcut doesn't support `--flag` arguments, which are used in a +lot of `wp` commands. As an alternative, a shell alias is provided: + +``` +source shell-aliases +wp post list --post_type page +``` diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f83397e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +--- +version: "3" + +services: + wordpress: + image: "wordpress:6.5.3" + ports: + - "80:80" + dns: 4.2.2.4 + volumes: + - "./entrypoint.sh:/usr/local/bin/entrypoint.sh:z" + - "./mailhog-smtp.php:/var/www/html/wp-content/mu-plugins/mailhog-smtp.php:z" + - "./wp-content:/var/www/html/wp-content/:z" + - "./composer.json:/var/www/html/composer.json:z" + - "./composer.lock:/var/www/html/composer.lock:z" + entrypoint: ["/usr/local/bin/entrypoint.sh"] + networks: + - backend + environment: + - WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST:-db} + - WORDPRESS_DB_USER=${WORDPRESS_DB_USER:-wordpress} + - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD:-wordpress} + - WORDPRESS_DB_NAME=wordpress + - WORDPRESS_CONFIG_EXTRA=${WORDPRESS_CONFIG_EXTRA} + - WORDPRESS_DEBUG=${WORDPRESS_DEBUG} + - PHP_EXTENSIONS=calendar + - PAGER=more + container_name: "${PROJECT_NAME}_wordpress" + + db: + image: "mariadb:10.6" + volumes: + - "${MARIADB_VOLUME:-mariadb}:/var/lib/mysql" + networks: + - backend + environment: + - MYSQL_ROOT_PASSWORD=wordpress + - MYSQL_DATABASE=wordpress + - MYSQL_USER=wordpress + - MYSQL_PASSWORD=wordpress + container_name: "${PROJECT_NAME}_db" + + mailhog: + image: "mailhog/mailhog" + networks: + - backend + ports: + - "8025:8025" + container_name: "${PROJECT_NAME}_mailhog" + +volumes: + mariadb: + +networks: + backend: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..7940e9c --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +if [ -n "$PHP_EXTENSIONS" ]; then + for extension in $PHP_EXTENSIONS; do + if ! php -m | grep -q $extension; then + docker-php-ext-install $PHP_EXTENSIONS + fi + done +fi + +if ! id -u "user" >/dev/null 2>&1; then + useradd -u 1000 -m user + mkdir /var/www/html/vendor + chown -R user:user /var/www/html/vendor +fi + +if [ ! -x /usr/bin/zip ]; then + apt update && apt install unzip +fi + +if [ ! -x /usr/local/bin/wp ]; then + curl -z /usr/local/bin/wp -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar + chmod +x /usr/local/bin/wp +fi + +if [ -n "$USE_COMPOSER" ] && [ ! -x /usr/local/bin/composer ]; then + mkdir -p /var/www/.composer + chown user:user /var/www/.composer + + curl https://getcomposer.org/installer -o /tmp/composer-setup.php + php -r "if (hash_file('sha384', '/tmp/composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" + php /tmp/composer-setup.php + rm /tmp/composer-setup.php + + mv /var/www/html/composer.phar /usr/local/bin/composer +fi + +export APACHE_RUN_USER=user +export APACHE_RUN_GROUP=user + +if [ -n "$@" ]; then + "$@" +fi + +# Upstream ENTRYPOINT +# https://github.com/docker-library/wordpress/blob/master/php7.4/apache/Dockerfile#L120 +/usr/local/bin/docker-entrypoint.sh apache2-foreground diff --git a/mailhog-smtp.php b/mailhog-smtp.php new file mode 100644 index 0000000..be9b2e1 --- /dev/null +++ b/mailhog-smtp.php @@ -0,0 +1,21 @@ +isSMTP(); + $phpmailer->SMTPAuth = false; + $phpmailer->SMTPSecure = false; + $phpmailer->SMTPAutoTLS = false; + $phpmailer->Host = "mailhog"; + $phpmailer->Port = 1025; + $phpmailer->From = "noreply@radhr.localhost"; + $phpmailer->FromName = "noreply@radhr.localhost"; + $phpmailer->Username = null; + $phpmailer->Password = null; +}); diff --git a/makefile b/makefile new file mode 100644 index 0000000..f46eb40 --- /dev/null +++ b/makefile @@ -0,0 +1,146 @@ +include .env + +.PHONY: up down stop prune ps shell shell_root wp logs + +default: up + +####################################### +# Variable admin +####################################### + +REQUIRED_BINS := docker +$(foreach bin,$(REQUIRED_BINS),\ + $(if $(shell command -v $(bin) 2> /dev/null),$(true),$(error Please install `$(bin)`))) + +ifeq ($(SITE_URL),) + $(error SITE_URL is not set) +endif + +ABRA ?= abra + +DOCKER_COMPOSE ?= docker-compose + +ifeq ($(DOCKER_SUDO), 1) + DOCKER = sudo docker + _DOCKER_COMPOSE = sudo $(DOCKER_COMPOSE) +else + DOCKER = docker + _DOCKER_COMPOSE = $(DOCKER_COMPOSE) +endif + +####################################### +# Core commands +####################################### + +## Start up containers. +up: + @echo "Starting up containers for $(PROJECT_NAME)..." + $(_DOCKER_COMPOSE) pull + $(_DOCKER_COMPOSE) up -d --remove-orphans + +## Stop containers. +down: stop + +## Start containers without updating. +start: + @echo "Starting containers for $(PROJECT_NAME) from where you left off..." + @$(_DOCKER_COMPOSE) start + +## Stop containers. +stop: + @echo "Stopping containers for $(PROJECT_NAME)..." + @$(_DOCKER_COMPOSE) stop + +## Remove containers and their volumes. +## You can optionally pass an argument with the service name to prune single container +prune: + @echo "Removing containers for $(PROJECT_NAME)..." + @$(_DOCKER_COMPOSE) down -v $(filter-out $@,$(MAKECMDGOALS)) + +ps: + @$(_DOCKER_COMPOSE) ps + +shell: + @$(_DOCKER_COMPOSE) exec -u user wordpress bash + +shell_root: + @$(_DOCKER_COMPOSE) exec wordpress bash + +## Executes `wp cli` +## Doesn't support --flag arguments. +wp: + $(_DOCKER_COMPOSE) exec -u user wordpress wp $(filter-out $@,$(MAKECMDGOALS)) + +## composer +## Doesn't support --flag arguments. +composer: + $(_DOCKER_COMPOSE) exec -u user wordpress composer $(filter-out $@,$(MAKECMDGOALS)) + +## Show vontainers' logs +## You can optinally pass an argument with the service name to limit logs +logs: + @$(_DOCKER_COMPOSE) logs -f $(filter-out $@,$(MAKECMDGOALS)) + +## Check that all required variables are defined +check: + @echo "$$(tput setaf 125)Watch out for any lines starting '-', which indicate settings in .env.sample which aren't in .env$$(tput sgr0)" + diff -u <(grep -v '^#' .env.sample | grep -v '^$$' | sed -e 's/=.*//g' | sort) <(grep -v '^#' .env | grep -v '^$$' | sed -e 's/=.*//g' | sort) || true + @echo "$$(tput setaf 125)The following command shouldn't show any differences; if it does, re-copy WORDPRESS_CONFIG_EXTRA fr4om .env.sample to .env$$(tput sgr0)" + diff -wu <(grep 'CONFIG_EXTRA' .env.sample ) <(grep 'CONFIG_EXTRA' .env) + +####################################### +# Content management +####################################### + +## Download wp-content files from site +uploads_fetch: + @echo -n "About to download ~1.5GB of data, overwriting existing data/uploads.tar.gz. - are you sure? [Y/n] " && read ans && if [ $${ans:-'Y'} = 'n' ]; then \ + printf $(_ERROR) "Aborting as requested\n"; \ + exit 1 ; \ + else \ + printf $(_SUCCESS) "OK" "Continuing" ; \ + $(ABRA) app run --no-tty $(SITE_URL) app tar --owner=0 --group=0 --no-same-owner --no-same-permissions -czf- /var/www/html/wp-content/uploads/ > data/uploads.tar.gz; \ + fi + +## Load latest wp-content from data/uploads.tar.gz +uploads_load: + tar -C wp-content --strip-components=4 -xzf data/uploads.tar.gz + +####################################### +# Wacky commands you probably won't need to use +####################################### + +## Download database from dev site +db_fetch: + $(ABRA) app run $(SITE_URL) db bash -c 'mariadb-dump -u root -p"$$(cat /run/secrets/db_root_password)" wordpress' | gzip > data/dbdump.sql.gz + +## Load latest database from ~/.abra/backups +db_load: + zcat data/dbdump.sql.gz | $(_DOCKER_COMPOSE) exec -T db mysql -u wordpress -pwordpress wordpress + +## Replace site URL +fix_url: + $(_DOCKER_COMPOSE) exec -u user wordpress wp --url=https://$(SITE_URL) search-replace --all-tables-with-prefix 'https://$(SITE_URL)' 'http://$(PROJECT_NAME).localhost' + +set_local_password: + $(_DOCKER_COMPOSE) exec -u user wordpress wp user update $(USERNAME) --user_pass=password + +db_pull: db_fetch db_load fix_url + +## Sync wp-content from site +uploads_pull: uploads_fetch uploads_load + +## Download wp-content files from site +plugins_fetch: + $(ABRA) app run --no-tty $(SITE_URL) app tar --owner=0 --group=0 --no-same-owner --no-same-permissions -czf- /var/www/html/wp-content/plugins/ > data/plugins.tar.gz + +## Load latest plugins from data/plugins.tar.gz +plugins_load: + tar -C wp-content --strip-components=4 -xzf data/plugins.tar.gz + +## Sync plugins from site +plugins_pull: plugins_fetch plugins_load + +# "Arguments" for makefiles.. +# https://stackoverflow.com/a/6273809/1826109 +%: