The first real upstream release since the subtree landed, and the point of
the whole arrangement. It merged cleanly: 7.1.2 changes about.php,
template.php and version.php, none of which this fork touches, so the patched
installer came through byte-identical and there was nothing to resolve.
Getting there needed two fixes to the tool, both of which only a real release
could have found — the earlier same-version run was a no-op that exercised
none of this.
**The prefix was an absolute path.** `${here#"$repo"/}` assumes the two
strings share a spelling, and on Windows they do not: --show-toplevel answers
"D:/Dev/…" while $PWD is "/d/Dev/…", so the subtraction left the path
untouched and `git subtree merge --prefix` was handed something absolute. The
same bug was fixed in refresh-patches.sh a few commits ago; this is the other
copy of it. Both now ask git via `rev-parse --show-prefix`.
**git-subtree refuses to run in a dirty repository** — any modification
anywhere, not just under the subtree. In a monorepo shared with other work
that is the normal state, so the tool was unusable exactly where it lives.
The merge now happens in a scratch worktree, which is clean by construction,
and comes back as one ordinary merge commit that touches only wordpress/ and
so does not care what else is modified.
Also: a failed run no longer refuses to retry. The import onto the upstream
branch is idempotent now, and the failure message distinguishes "upstream and
the fork changed the same lines" from "the merge could not start", instead of
blaming a conflict for both.
228 lines
8.4 KiB
Bash
228 lines
8.4 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.
|
|
#
|
|
# The merge happens in a temporary worktree, not in your checkout. git-subtree
|
|
# refuses to run at all when anything in the repository is modified, and in a
|
|
# monorepo shared with other work that is the normal state — the merge would
|
|
# be blocked by uncommitted files it does not touch. A worktree is clean by
|
|
# construction, and the result comes back as one ordinary merge commit.
|
|
#
|
|
# Nothing is pushed. Run it, look at the merge, run the tests, then push.
|
|
|
|
set -euo pipefail
|
|
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
repo="$(git -C "$here" rev-parse --show-toplevel)"
|
|
# Ask git for the path rather than subtracting strings: on Windows
|
|
# --show-toplevel answers "D:/…" while $PWD is "/d/…", and the subtraction
|
|
# silently leaves an absolute path, which --prefix then rejects.
|
|
prefix="$(cd "$here" && git rev-parse --show-prefix)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."
|
|
|
|
# The merge lands on top of whatever is committed, so anything staged or
|
|
# modified under the subtree itself would be lost or fought over.
|
|
if ! git -C "$repo" diff --quiet -- "$prefix" 2>/dev/null; then
|
|
die "${prefix}/ 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
|
|
|
|
IMPORT_TREE="$here/dist/.vendor-import"
|
|
MERGE_TREE="$here/dist/.vendor-merge"
|
|
MERGE_BRANCH="sirius-press/_merge-${VERSION}"
|
|
|
|
drop_worktree() {
|
|
git -C "$repo" worktree remove --force "$1" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
say "importing the pristine tree onto $UPSTREAM_BRANCH"
|
|
drop_worktree "$IMPORT_TREE"
|
|
rm -rf "$IMPORT_TREE"
|
|
git -C "$repo" worktree add --quiet "$IMPORT_TREE" "$UPSTREAM_BRANCH"
|
|
trap 'drop_worktree "$IMPORT_TREE"' EXIT
|
|
|
|
# Replace the tree wholesale: files upstream deleted have to disappear, or the
|
|
# subtree merge would keep resurrecting them.
|
|
find "$IMPORT_TREE" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
|
|
tar -xzf "$TARBALL" -C "$IMPORT_TREE" --strip-components=1
|
|
|
|
git -C "$IMPORT_TREE" add -A
|
|
if git -C "$IMPORT_TREE" diff --cached --quiet; then
|
|
# Already imported — a previous run got this far and then stopped. Carry on
|
|
# to the merge rather than refusing, so a failure is retryable.
|
|
say "WordPress $VERSION was already imported; continuing to the merge"
|
|
else
|
|
git -C "$IMPORT_TREE" \
|
|
-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 "$IMPORT_TREE" rev-parse --short HEAD)"
|
|
fi
|
|
|
|
drop_worktree "$IMPORT_TREE"
|
|
trap - EXIT
|
|
|
|
# ------------------------------------------------------------ subtree merge
|
|
|
|
say "merging into ${prefix}/ (in a scratch worktree)"
|
|
drop_worktree "$MERGE_TREE"
|
|
rm -rf "$MERGE_TREE"
|
|
git -C "$repo" branch -D "$MERGE_BRANCH" >/dev/null 2>&1 || true
|
|
git -C "$repo" worktree add --quiet -b "$MERGE_BRANCH" "$MERGE_TREE" HEAD
|
|
|
|
if git -C "$MERGE_TREE" \
|
|
-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
|
|
say "merged cleanly"
|
|
else
|
|
cat >&2 <<EOF
|
|
|
|
$(printf '\033[31mThe merge did not complete.\033[0m')
|
|
|
|
Usually this means upstream changed code the fork also changes — in practice
|
|
wp-admin/install.php, the only file this fork patches. Your own checkout is
|
|
untouched and still on WordPress ${CURRENT}; the half-done merge is in a
|
|
scratch worktree:
|
|
|
|
cd ${MERGE_TREE}
|
|
git status # what conflicted
|
|
\$EDITOR ${prefix}/wp-admin/install.php
|
|
git add ${prefix}/wp-admin/install.php
|
|
git commit # finish the merge
|
|
|
|
Then bring it back and finish up:
|
|
|
|
cd ${repo}
|
|
git merge --no-ff ${MERGE_BRANCH}
|
|
git worktree remove ${MERGE_TREE}
|
|
git branch -d ${MERGE_BRANCH}
|
|
${here}/tools/refresh-patches.sh
|
|
# set WP_VERSION / WP_URL / WP_SHA256 / WP_SHA1 in tools/wordpress.lock
|
|
|
|
EOF
|
|
exit 1
|
|
fi
|
|
|
|
# Bring the merge home. This touches only ${prefix}/, so unrelated modified
|
|
# files elsewhere in the repository are not in its way.
|
|
say "bringing the merge into the working branch"
|
|
git -C "$repo" merge --no-ff -q \
|
|
-m "merge: WordPress ${VERSION} into ${prefix}/" "$MERGE_BRANCH" \
|
|
|| die "could not merge ${MERGE_BRANCH} into the working branch. It is still
|
|
there, with the subtree merge already done — resolve and merge it by hand."
|
|
|
|
drop_worktree "$MERGE_TREE"
|
|
git -C "$repo" branch -D "$MERGE_BRANCH" >/dev/null 2>&1 || true
|
|
|
|
# --------------------------------------------------------------- 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" >/dev/null || 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 subtree merge is committed. tools/wordpress.lock and patches/ are changed
|
|
but not committed — look at them, then commit. 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
|