The subtree is in place, so everything that used to fetch and patch core at
build time now just copies it.
tools/build.sh copies wordpress/ — no download, no checksum step,
because there is nothing to fetch and nothing to
trust that is not already in the repository
docker/Dockerfile COPY wordpress/ instead of curl + sha256 + patch;
the build args and the `patch` package are gone
docker-compose.yml no WP_VERSION / WP_URL / WP_SHA256 to keep in step
tools/update-wordpress.sh is rewritten around what the subtree makes
possible. It imports the pristine release onto sirius-press/wordpress-upstream
and then `git subtree merge`s that branch, which three-way merges upstream
against the fork's own commit. A patch either applies with fuzz and hopes or
fails and leaves you re-deriving the change by hand; a merge conflict is
resolved once, in the file, and the next release merges against the
resolution.
patches/ survives as documentation rather than mechanism, and is now
generated: tools/refresh-patches.sh diffs the subtree against the pristine
import and rewrites the directory, with --check for CI. It answers the
question anyone auditing a fork asks first — what exactly did you change
inside WordPress? — in a minute, which `git log wordpress/` cannot, because
that log is mostly upstream imports. Generated documentation stays true; a
hand-maintained record of a core diff drifts, and a stale one is worse than
none because people trust it.
One test change worth noting: the syntax sweep no longer walks all of
wordpress/. It lints the fork's own PHP plus every core file patches/ says
the fork touches, which keeps the suite at seven seconds instead of a minute
while still covering the only core file that can break.
195 lines
6.6 KiB
Bash
195 lines
6.6 KiB
Bash
#!/usr/bin/env bash
|
|
# update-wordpress.sh — bring a new WordPress release into the fork.
|
|
#
|
|
# tools/update-wordpress.sh 7.1.2
|
|
#
|
|
# Two steps, and the second is the one that matters:
|
|
#
|
|
# 1. Import the pristine release onto the `sirius-press/wordpress-upstream`
|
|
# branch — one commit per version, nothing but upstream, never edited.
|
|
# 2. `git subtree merge` that branch into wordpress/, which three-way merges
|
|
# it against the fork's own commits on top of the last import.
|
|
#
|
|
# That second step is why core is vendored rather than patched at build time.
|
|
# A three-way merge understands that upstream changed lines A and B while the
|
|
# fork changed line C, and only stops when they overlap. It also leaves a
|
|
# conflict you resolve once, in the file, instead of a patch you re-derive
|
|
# every release.
|
|
#
|
|
# Nothing is pushed. Run it, look at the merge, run the tests, then commit.
|
|
|
|
set -euo pipefail
|
|
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
repo="$(git -C "$here" rev-parse --show-toplevel)"
|
|
prefix="${here#"$repo"/}/wordpress"
|
|
|
|
VERSION="${1:-}"
|
|
|
|
say() { printf '\033[1m→\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; }
|
|
die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
[ -n "$VERSION" ] || die "usage: tools/update-wordpress.sh <version>"
|
|
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] || die "'$VERSION' does not look like a WordPress version"
|
|
|
|
# shellcheck source=wordpress.lock
|
|
source "$here/tools/wordpress.lock"
|
|
CURRENT="$WP_VERSION"
|
|
[ "$VERSION" != "$CURRENT" ] || die "the fork is already on WordPress $VERSION"
|
|
|
|
UPSTREAM_BRANCH="sirius-press/wordpress-upstream"
|
|
git -C "$repo" rev-parse --verify --quiet "$UPSTREAM_BRANCH" >/dev/null \
|
|
|| die "the branch $UPSTREAM_BRANCH is missing. It holds the pristine upstream
|
|
imports that the subtree merges against; without it this fork cannot take an
|
|
upstream release. See docs/upstream-merges.md."
|
|
|
|
# A subtree merge writes to the working tree, so it has to be clean — at least
|
|
# for the paths involved. Refuse early rather than half way through.
|
|
if ! git -C "$repo" diff --quiet -- "$prefix" 2>/dev/null; then
|
|
die "wordpress/ has uncommitted changes. Commit or stash them first."
|
|
fi
|
|
|
|
CACHE="$here/dist/.cache"
|
|
mkdir -p "$CACHE"
|
|
URL="https://wordpress.org/wordpress-${VERSION}.tar.gz"
|
|
TARBALL="$CACHE/wordpress-${VERSION}.tar.gz"
|
|
|
|
# ------------------------------------------------------------------- fetch
|
|
|
|
if [ ! -f "$TARBALL" ]; then
|
|
say "downloading WordPress $VERSION"
|
|
curl -fsSL -o "$TARBALL.part" "$URL" || die "could not download $URL — does that version exist?"
|
|
mv "$TARBALL.part" "$TARBALL"
|
|
fi
|
|
|
|
say "checking it against the SHA-1 wordpress.org publishes"
|
|
published="$(curl -fsSL "${URL}.sha1" 2>/dev/null || true)"
|
|
actual_sha1="$(sha1sum "$TARBALL" | cut -d' ' -f1)"
|
|
if [ -z "$published" ]; then
|
|
warn "wordpress.org served no .sha1 for this release; recording the sha256 below unverified"
|
|
elif [ "$published" != "$actual_sha1" ]; then
|
|
rm -f "$TARBALL"
|
|
die "SHA-1 mismatch — the download is not what wordpress.org publishes.
|
|
published $published
|
|
got $actual_sha1"
|
|
fi
|
|
NEW_SHA256="$(sha256sum "$TARBALL" | cut -d' ' -f1)"
|
|
|
|
# ------------------------------------------- import onto the upstream branch
|
|
|
|
WORKTREE="$here/dist/.vendor-import"
|
|
say "importing the pristine tree onto $UPSTREAM_BRANCH"
|
|
rm -rf "$WORKTREE"
|
|
git -C "$repo" worktree add --quiet "$WORKTREE" "$UPSTREAM_BRANCH"
|
|
|
|
cleanup() {
|
|
git -C "$repo" worktree remove --force "$WORKTREE" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# Replace the tree wholesale: files upstream deleted have to disappear, or the
|
|
# subtree merge would keep resurrecting them.
|
|
find "$WORKTREE" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
|
|
tar -xzf "$TARBALL" -C "$WORKTREE" --strip-components=1
|
|
|
|
git -C "$WORKTREE" add -A
|
|
if git -C "$WORKTREE" diff --cached --quiet; then
|
|
die "WordPress $VERSION is byte-identical to what is already imported."
|
|
fi
|
|
|
|
git -C "$WORKTREE" \
|
|
-c user.name="Silent Mode" -c user.email="hephaestus@silentmode.st" \
|
|
commit -q -m "WordPress ${VERSION}
|
|
|
|
Pristine upstream, unpacked from the official wordpress.org tarball.
|
|
|
|
${URL}
|
|
sha1 ${actual_sha1} (published by wordpress.org)
|
|
sha256 ${NEW_SHA256}
|
|
|
|
This branch carries nothing but upstream releases, one commit each, and is
|
|
never edited."
|
|
|
|
say "imported as $(git -C "$WORKTREE" rev-parse --short HEAD)"
|
|
cleanup
|
|
trap - EXIT
|
|
|
|
# ------------------------------------------------------------ subtree merge
|
|
|
|
say "merging into ${prefix}/"
|
|
if git -C "$repo" \
|
|
-c user.name="Silent Mode" -c user.email="hephaestus@silentmode.st" \
|
|
subtree merge --prefix="$prefix" "$UPSTREAM_BRANCH" \
|
|
-m "merge: WordPress ${VERSION} into the vendored subtree"
|
|
then
|
|
merged=1
|
|
else
|
|
merged=0
|
|
fi
|
|
|
|
if [ "$merged" -eq 0 ]; then
|
|
cat >&2 <<EOF
|
|
|
|
$(printf '\033[31mThe merge stopped on a conflict.\033[0m')
|
|
|
|
Upstream changed code the fork also changes — almost certainly
|
|
wp-admin/install.php, the only file this fork patches.
|
|
|
|
git status # what conflicted
|
|
git diff # the overlap
|
|
\$EDITOR ${prefix}/wp-admin/install.php
|
|
git add ${prefix}/wp-admin/install.php
|
|
git commit # finish the merge
|
|
|
|
Then regenerate the readable copy of the diff and update the lock:
|
|
|
|
tools/refresh-patches.sh
|
|
# set WP_VERSION / WP_URL / WP_SHA256 / WP_SHA1 in tools/wordpress.lock
|
|
|
|
EOF
|
|
exit 1
|
|
fi
|
|
|
|
# --------------------------------------------------------------- the lock
|
|
|
|
say "updating tools/wordpress.lock"
|
|
python3 - "$VERSION" "$URL" "$NEW_SHA256" "$actual_sha1" "$here/tools/wordpress.lock" <<'PY'
|
|
import io, sys
|
|
version, url, sha256, sha1, path = sys.argv[1:6]
|
|
fields = {
|
|
'WP_VERSION=': version,
|
|
'WP_URL=': url,
|
|
'WP_SHA256=': sha256,
|
|
'WP_SHA1=': sha1,
|
|
}
|
|
out = []
|
|
for line in io.open(path, encoding='utf-8'):
|
|
for key, value in fields.items():
|
|
if line.startswith(key):
|
|
line = f'{key}{value}\n'
|
|
break
|
|
out.append(line)
|
|
io.open(path, 'w', encoding='utf-8', newline='').write(''.join(out))
|
|
PY
|
|
|
|
if [ -x "$here/tools/refresh-patches.sh" ]; then
|
|
say "refreshing patches/ so it still describes the fork's core diff"
|
|
"$here/tools/refresh-patches.sh" || warn "could not refresh patches/ — do it by hand"
|
|
fi
|
|
|
|
cat <<EOF
|
|
|
|
$(printf '\033[32mSirius Press now builds on WordPress %s.\033[0m' "$VERSION")
|
|
|
|
${CURRENT} -> ${VERSION}
|
|
|
|
The merge and the lock update are staged as commits already; patches/ may
|
|
have changed too. Before pushing:
|
|
|
|
tests/run.sh
|
|
tools/build.sh
|
|
then walk through wp-admin/install.php once — the setup wizard is the only
|
|
file this fork patches, so it is the only thing this can have broken.
|
|
|
|
EOF
|