diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..eb937d5934 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,117 @@ +# Fork of docker-library/wordpress: every week, merge upstream into master then +# build the WordPress branches x PHP versions used by our sites, each with its +# latest WordPress patch and the latest PHP patch (php:X.Y-fpm-alpine). +# Our files live in .circleci/ and dow/ only, so upstream merges never conflict. +version: 2.1 + +orbs: + aws-cli: circleci/aws-cli@5.4.1 + aws-ecr: circleci/aws-ecr@9.8.1 + +executors: + build-executor: + machine: + image: default + resource_class: medium + +jobs: + sync-upstream: + docker: + - image: cimg/base:current + resource_class: small + steps: + # no "checkout": the read-only checkout key would be picked for the push + - add_ssh_keys: + fingerprints: + - "SHA256:YvxD+dpQBhbZ0NqMC2rAbTXr0Xr6svDWZaVKBXLBuHk" + - run: + name: Merge docker-library/wordpress into master + command: | + mkdir -p ~/.ssh + ssh-keyscan -t ed25519 github.com >> ~/.ssh/known_hosts + git clone --branch master "git@github.com:${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git" . + git remote add upstream https://github.com/docker-library/wordpress.git + git fetch upstream master + git -c user.name='CircleCI' -c user.email='circleci@users.noreply.github.com' \ + merge --no-edit upstream/master + git push origin master + - persist_to_workspace: + root: . + paths: [.] + + build: + parameters: + version: + description: '"-php", e.g. 6.8-php8.3' + type: string + executor: build-executor + steps: + - attach_workspace: + at: . + - run: + name: Render Dockerfile + command: | + command -v gawk > /dev/null || { sudo apt-get update && sudo apt-get install -y gawk; } + dow/prepare.sh << parameters.version >> >> "$BASH_ENV" + source "$BASH_ENV" + docker run --rm "php:${PHP_VERSION}-fpm-alpine" php -r 'echo "PHP ", PHP_VERSION, PHP_EOL;' + - aws-ecr/build_and_push_image: + auth: + - aws-cli/setup: + role_arn: ${AWS_ROLE_ARN} + checkout: false + path: ${BUILD_DIR} + build_path: ${BUILD_DIR} + extra_build_args: --provenance=false + repo: asmodee-services/wordpress + create_repo: true + tag: << parameters.version >>-fpm-alpine,${WP_FULL_VERSION}-php${PHP_VERSION}-fpm-alpine + + trigger-wordpress-base: + docker: + - image: cimg/base:current + resource_class: small + steps: + - run: + name: Trigger docker-wordpress-base master pipeline + command: | + curl --fail-with-body -sS -X POST \ + -H "Circle-Token: ${CIRCLE_TOKEN}" \ + -H 'Content-Type: application/json' \ + -d '{"branch": "master"}' \ + https://circleci.com/api/v2/project/gh/daysofwonder/docker-wordpress-base/pipeline + +workflows: + # scheduled pipeline (Project Settings > Triggers), or "Trigger Pipeline" + # from the UI/API; never on push since sync-upstream pushes to master + weekly-build: + when: + or: + - equal: [scheduled_pipeline, << pipeline.trigger_source >>] + - equal: [api, << pipeline.trigger_source >>] + jobs: + - sync-upstream + + - build: + requires: [sync-upstream] + context: [aws-legacy] + matrix: + parameters: + # "-php" used by our sites + # (ARG WORDPRESS_BASE_VERSION of their Dockerfile), plus PHP 8.4 + # and 8.5 from WordPress 6.8 on; keep in sync with the + # docker-wordpress-base matrix (dow/Makefile reads this list) + version: + - "6.4-php8.2" + - "6.6-php8.2" + - "6.7-php8.2" + - "6.8-php8.4" + - "6.8-php8.5" + - "6.9-php8.4" + - "6.9-php8.5" + - "7.1-php8.4" + - "7.1-php8.5" + + - trigger-wordpress-base: + requires: [build] + context: [circleci-api] diff --git a/dow/.gitignore b/dow/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/dow/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/dow/Makefile b/dow/Makefile new file mode 100644 index 0000000000..8e65937371 --- /dev/null +++ b/dow/Makefile @@ -0,0 +1,44 @@ +# Local helpers around dow/prepare.sh, run from the repository root with +# "make -C dow ". The version list is the CircleCI build matrix. +# +# make -C dow list +# make -C dow build VERSION=6.8-php8.4 +# make -C dow test VERSION=6.8-php8.4 +# make -C dow build-all + +SHELL := bash +.SHELLFLAGS := -Eeuo pipefail -c + +CONFIG := ../.circleci/config.yml +VERSIONS := $(shell grep -oE '"[0-9]+\.[0-9]+-php[0-9]+\.[0-9]+"' $(CONFIG) | tr -d '"') +VERSION ?= +IMAGE := dow-wordpress + +.PHONY: list prepare build test build-all validate clean check-version + +list: + @printf '%s\n' $(VERSIONS) + +check-version: + @[ -n "$(VERSION)" ] || { echo >&2 'usage: make -C dow $(MAKECMDGOALS) VERSION=6.8-php8.4'; exit 1; } + +# render the Dockerfile in dow/build/ and print the resolved versions +prepare: check-version + ./prepare.sh $(VERSION) + +build: check-version + eval "$$(./prepare.sh $(VERSION))"; \ + docker build --pull -t $(IMAGE):$(VERSION)-fpm-alpine "$$BUILD_DIR" + +test: check-version + docker run --rm $(IMAGE):$(VERSION)-fpm-alpine sh -c \ + 'php -r "echo \"PHP \", PHP_VERSION, PHP_EOL;"; grep "^\$$wp_version" /usr/src/wordpress/wp-includes/version.php' + +build-all: + for v in $(VERSIONS); do $(MAKE) --no-print-directory build test VERSION=$$v; done + +validate: + circleci config validate --org-id b96fa597-f66e-4703-b4da-3792c03c93b2 $(CONFIG) + +clean: + rm -rf build diff --git a/dow/prepare.sh b/dow/prepare.sh new file mode 100755 index 0000000000..8c21c00cf3 --- /dev/null +++ b/dow/prepare.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# Renders the upstream Dockerfile.template for one WordPress branch and one PHP +# version, resolving the latest WordPress patch release of that branch. +# Upstream files are never modified: the rendering happens in dow/build/. +# +# dow/prepare.sh 6.8-php8.3 +# +# Prints shell exports on stdout (meant for "$BASH_ENV"), logs on stderr. + +cd "$(dirname "$(readlink -f "$BASH_SOURCE")")/.." + +combo="${1:?usage: $0 -php, e.g. 6.8-php8.3}" +wpBranch="${combo%-php*}" +phpVersion="${combo##*-php}" +variant='fpm-alpine' + +if [[ ! "$wpBranch" =~ ^[0-9]+\.[0-9]+$ || ! "$phpVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo >&2 "error: invalid '$combo', expected e.g. 6.8-php8.3" + exit 1 +fi + +# every released version is a key of stable-check, "X.Y" being the X.Y.0 release +upstream="$( + wget -qO- 'https://api.wordpress.org/core/stable-check/1.0/' \ + | jq -r --arg b "$wpBranch" 'keys[] | select(. == $b or startswith($b + "."))' \ + | sort -V \ + | tail -1 +)" +if [ -z "$upstream" ]; then + echo >&2 "error: no WordPress release found for branch $wpBranch" + exit 1 +fi +sha1="$(wget -qO- "https://wordpress.org/wordpress-$upstream.tar.gz.sha1")" +if [ -z "$sha1" ]; then + echo >&2 "error: no sha1 found for WordPress $upstream" + exit 1 +fi + +fullVersion="$upstream" +if [[ "$fullVersion" != *.*.* ]]; then + fullVersion+='.0' +fi +echo >&2 "WordPress $wpBranch -> $fullVersion (sha1 $sha1), PHP $phpVersion, $variant" + +work="dow/build/$combo" +rm -rf "$work" +mkdir -p "$work" +cp -a Dockerfile.template apply-templates.sh docker-entrypoint.sh wp-config-docker.php cli-entrypoint.sh "$work/" + +export wpBranch phpVersion variant upstream sha1 fullVersion +jq -n -S '{ + (env.wpBranch): { + version: env.fullVersion, + upstream: env.upstream, + sha1: env.sha1, + phpVersions: [ env.phpVersion ], + variants: [ env.variant ], + } +}' > "$work/versions.json" + +( cd "$work" && ./apply-templates.sh "$wpBranch" ) >&2 + +buildDir="$work/$wpBranch/php$phpVersion/$variant" +[ -f "$buildDir/Dockerfile" ] + +echo "export WP_FULL_VERSION='$fullVersion'" +echo "export PHP_VERSION='$phpVersion'" +echo "export BUILD_DIR='$PWD/$buildDir'"