wordmove-ng 6.0.1 → 6.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +21 -20
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +14 -0
- data/CLAUDE.md +2 -1
- data/README.md +18 -6
- data/contrib/wordmove-sync.sh +73 -0
- data/docs/automation.md +166 -0
- data/docs/contributing.md +5 -3
- data/docs/index.md +1 -0
- data/docs/installation.md +117 -4
- data/docs/troubleshooting.md +1 -1
- data/docs/usage.md +4 -0
- data/lib/wordmove/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b2ca340ce83622a7faa03d89c41573efb50933bd3c85f5427eac9f9ae07ee91
|
|
4
|
+
data.tar.gz: 9183010aadcc92084a70839d140bd62604c8e4058aac8411b809f70558e14d7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7411e375d8221a234dcb394ada25d0c3caa7e62225a328d5cd78d25f9d4a5be8887227844126d6045abd339b1c7c3b74966894d9fef5159c0e1fc1eab909a79e
|
|
7
|
+
data.tar.gz: a1914ff1d4a9ed0b533588bd1aca0b13157576e0e4d731c326edaf54db72916524d2402460350b3d0315d3ca623acf870d57c800b04a6c21955cd301cc333952
|
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
#
|
|
3
3
|
# 1. release-please watches master. From Conventional Commits it opens (and keeps
|
|
4
4
|
# updating) a "release PR" that bumps lib/wordmove/version.rb and CHANGELOG.md.
|
|
5
|
-
# Merging that PR creates the vX.Y.Z tag and the GitHub release
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
5
|
+
# Merging that PR creates the vX.Y.Z tag and the GitHub release, using the
|
|
6
|
+
# RELEASE_PLEASE_TOKEN PAT so that the tag push triggers this workflow again.
|
|
7
|
+
# 2. That tag push runs the publish job, which builds the gem, pushes it to
|
|
8
|
+
# rubygems.org with trusted publishing (OIDC, no API key) and attaches the
|
|
9
|
+
# .gem to the release. A v* tag pushed by hand at the head of master goes
|
|
10
|
+
# through the same job.
|
|
11
11
|
#
|
|
12
12
|
# One-time setup (see README "Releasing"):
|
|
13
13
|
# - rubygems.org: pending trusted publisher for gem wordmove-ng, repository
|
|
14
14
|
# tekgnosis-net/wordmove-ng, workflow release.yml, environment release
|
|
15
15
|
# - GitHub: environment "release"; Actions setting "Allow GitHub Actions to
|
|
16
|
-
# create and approve pull requests" enabled
|
|
16
|
+
# create and approve pull requests" enabled; repository secret
|
|
17
|
+
# RELEASE_PLEASE_TOKEN holding a fine-grained PAT scoped to this repository
|
|
18
|
+
# with Contents and Pull requests read/write (so release PRs run the checks
|
|
19
|
+
# that branch protection requires)
|
|
17
20
|
|
|
18
21
|
name: Release
|
|
19
22
|
|
|
@@ -33,25 +36,23 @@ jobs:
|
|
|
33
36
|
permissions:
|
|
34
37
|
contents: write
|
|
35
38
|
pull-requests: write
|
|
36
|
-
outputs:
|
|
37
|
-
release_created: ${{ steps.release.outputs.release_created }}
|
|
38
|
-
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
39
39
|
steps:
|
|
40
|
+
# A fine-grained PAT (secret RELEASE_PLEASE_TOKEN, contents + pull-requests
|
|
41
|
+
# read/write) instead of the built-in token: PRs opened with the built-in
|
|
42
|
+
# token never trigger the Tests workflow, which the branch protection on
|
|
43
|
+
# master requires before a release PR can be merged.
|
|
40
44
|
- uses: googleapis/release-please-action@v4
|
|
41
45
|
id: release
|
|
42
46
|
with:
|
|
47
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
43
48
|
config-file: release-please-config.json
|
|
44
49
|
manifest-file: .release-please-manifest.json
|
|
45
50
|
|
|
46
51
|
publish:
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
if:
|
|
51
|
-
always() && (
|
|
52
|
-
needs.release-please.outputs.release_created == 'true' ||
|
|
53
|
-
startsWith(github.ref, 'refs/tags/v')
|
|
54
|
-
)
|
|
52
|
+
# Only on tag pushes. release-please's tag (created with the PAT) triggers
|
|
53
|
+
# this workflow like any other push, so publishing from the master run as
|
|
54
|
+
# well would race it and fail with "Tag vX.Y.Z has already been created".
|
|
55
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
55
56
|
runs-on: ubuntu-latest
|
|
56
57
|
environment: release
|
|
57
58
|
permissions:
|
|
@@ -72,7 +73,7 @@ jobs:
|
|
|
72
73
|
|
|
73
74
|
- name: Verify the tag points at the head of master
|
|
74
75
|
env:
|
|
75
|
-
TAG: ${{
|
|
76
|
+
TAG: ${{ github.ref_name }}
|
|
76
77
|
run: |
|
|
77
78
|
git fetch --tags --force
|
|
78
79
|
tag_commit="$(git rev-parse "refs/tags/$TAG^{commit}")"
|
|
@@ -96,7 +97,7 @@ jobs:
|
|
|
96
97
|
- name: Attach the gem to the GitHub release
|
|
97
98
|
env:
|
|
98
99
|
GH_TOKEN: ${{ github.token }}
|
|
99
|
-
TAG: ${{
|
|
100
|
+
TAG: ${{ github.ref_name }}
|
|
100
101
|
# release-please creates the release itself; a hand-pushed tag has none yet.
|
|
101
102
|
run: |
|
|
102
103
|
if ! gh release view "$TAG" >/dev/null 2>&1; then
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to wordmove-ng are documented here. The project follows
|
|
|
5
5
|
are listed at https://github.com/welaika/wordmove/releases; the kokiddp fork's changes
|
|
6
6
|
between 5.2.2 and this project are summarised under 6.0.0.
|
|
7
7
|
|
|
8
|
+
## [6.0.3](https://github.com/tekgnosis-net/wordmove-ng/compare/v6.0.2...v6.0.3) (2026-09-30)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
* expand the Ruby installation guide ([#7](https://github.com/tekgnosis-net/wordmove-ng/issues/7)) ([5972e2c](https://github.com/tekgnosis-net/wordmove-ng/commit/5972e2cf45f8ef6ebf1c2724b7637a8f4d319e11))
|
|
14
|
+
|
|
15
|
+
## [6.0.2](https://github.com/tekgnosis-net/wordmove-ng/compare/v6.0.1...v6.0.2) (2026-09-12)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Documentation
|
|
19
|
+
|
|
20
|
+
* add cron automation guide and contrib/wordmove-sync.sh ([#4](https://github.com/tekgnosis-net/wordmove-ng/issues/4)) ([dbe3612](https://github.com/tekgnosis-net/wordmove-ng/commit/dbe36126976f9f5a0f0793208aed89bd5c7fc787))
|
|
21
|
+
|
|
8
22
|
## [6.0.1](https://github.com/tekgnosis-net/wordmove-ng/compare/v6.0.0...v6.0.1) (2026-09-09)
|
|
9
23
|
|
|
10
24
|
|
data/CLAUDE.md
CHANGED
|
@@ -103,7 +103,8 @@ Update the relevant page in the same commit as any user-facing behaviour change.
|
|
|
103
103
|
`docs:`, `chore:`, `ci:`, `test:`, `refactor:`). release-please derives the version bump
|
|
104
104
|
and CHANGELOG from them; never edit `lib/wordmove/version.rb` or `CHANGELOG.md` by hand.
|
|
105
105
|
Releases are published to rubygems.org by `.github/workflows/release.yml` (trusted
|
|
106
|
-
publishing,
|
|
106
|
+
publishing). `master` is protected for everyone including admins: branch, open a PR, let
|
|
107
|
+
the six `test` checks pass, merge. release-please needs the `RELEASE_PLEASE_TOKEN` secret.
|
|
107
108
|
|
|
108
109
|
- Every shell fragment that includes user/config data goes through `Shellwords.escape`
|
|
109
110
|
(or `Shellwords.split` for user-supplied option strings). Secrets must never appear in
|
data/README.md
CHANGED
|
@@ -35,7 +35,9 @@ in a few places where the old behaviour was unsafe. See [Upgrading from wordmove
|
|
|
35
35
|
|
|
36
36
|
## Installation
|
|
37
37
|
|
|
38
|
-
Ruby 3.0 or newer is required.
|
|
38
|
+
Ruby 3.0 or newer is required. If your system Ruby is older or missing, the docs walk
|
|
39
|
+
through [installing Ruby](https://tekgnosis-net.github.io/wordmove-ng/installation/#ruby)
|
|
40
|
+
with your package manager, rbenv, RVM, mise or Docker.
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
43
|
gem install wordmove-ng
|
|
@@ -246,12 +248,17 @@ production:
|
|
|
246
248
|
File sync mirrors the source: files missing on the source are deleted on the destination.
|
|
247
249
|
Put anything you need to keep in `exclude`, which is always relative to `wordpress_path`.
|
|
248
250
|
|
|
251
|
+
Scheduled syncs from cron or CI work out of the box; `contrib/wordmove-sync.sh` handles the
|
|
252
|
+
environment cron lacks (Ruby version manager, `PATH`, no agent, no TTY, overlap lock, logs).
|
|
253
|
+
See [Automation and cron](https://tekgnosis-net.github.io/wordmove-ng/automation/).
|
|
254
|
+
|
|
249
255
|
The documentation site has the full reference:
|
|
250
256
|
[Configuration](https://tekgnosis-net.github.io/wordmove-ng/configuration/),
|
|
251
257
|
[Usage and flags](https://tekgnosis-net.github.io/wordmove-ng/usage/),
|
|
252
258
|
[Database sync](https://tekgnosis-net.github.io/wordmove-ng/database-sync/),
|
|
253
259
|
[Hooks](https://tekgnosis-net.github.io/wordmove-ng/hooks/),
|
|
254
260
|
[Multiple environments](https://tekgnosis-net.github.io/wordmove-ng/environments/),
|
|
261
|
+
[Automation and cron](https://tekgnosis-net.github.io/wordmove-ng/automation/),
|
|
255
262
|
[Troubleshooting](https://tekgnosis-net.github.io/wordmove-ng/troubleshooting/).
|
|
256
263
|
|
|
257
264
|
## Logging
|
|
@@ -315,12 +322,12 @@ stored anywhere.
|
|
|
315
322
|
1. Every push to `master` updates a "release PR" that bumps `lib/wordmove/version.rb` and
|
|
316
323
|
`CHANGELOG.md` according to the commits since the last release.
|
|
317
324
|
2. Merging that PR creates the `vX.Y.Z` tag and the GitHub release.
|
|
318
|
-
3. The `publish` job in `.github/workflows/release.yml
|
|
319
|
-
tagged commit, builds the gem, pushes it to rubygems.org and
|
|
320
|
-
the GitHub release.
|
|
325
|
+
3. The tag push triggers the `publish` job in `.github/workflows/release.yml`, which runs
|
|
326
|
+
the test suite on the tagged commit, builds the gem, pushes it to rubygems.org and
|
|
327
|
+
attaches the `.gem` file to the GitHub release.
|
|
321
328
|
|
|
322
|
-
Pushing a `v*` tag by hand at the head of `master`
|
|
323
|
-
how 6.0.0 was cut. Merge the release PR only when there is something worth shipping:
|
|
329
|
+
Pushing a `v*` tag by hand at the head of `master` goes through the same publish job; that
|
|
330
|
+
is how 6.0.0 was cut. Merge the release PR only when there is something worth shipping:
|
|
324
331
|
release-please keeps proposing a patch release for any Conventional Commit, including
|
|
325
332
|
`ci:` and `docs:` ones.
|
|
326
333
|
|
|
@@ -333,6 +340,11 @@ One-time setup for a new maintainer or a fork:
|
|
|
333
340
|
- In the GitHub repository settings create an environment named `release`, and under
|
|
334
341
|
*Actions → General* enable "Allow GitHub Actions to create and approve pull requests"
|
|
335
342
|
so release-please can open its PR.
|
|
343
|
+
- Create a fine-grained personal access token scoped to this repository with *Contents* and
|
|
344
|
+
*Pull requests* set to read and write, and store it as the repository secret
|
|
345
|
+
`RELEASE_PLEASE_TOKEN`. Pull requests opened with the built-in Actions token never trigger
|
|
346
|
+
other workflows, so without it the release PR cannot satisfy the required `test` checks on
|
|
347
|
+
the protected `master` branch.
|
|
336
348
|
|
|
337
349
|
## Credits and licence
|
|
338
350
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Run a wordmove-ng sync from cron (or any non interactive context).
|
|
4
|
+
#
|
|
5
|
+
# Copy this file somewhere in your PATH, adjust the settings block or override
|
|
6
|
+
# the variables from the environment, then add a crontab entry such as
|
|
7
|
+
#
|
|
8
|
+
# MAILTO=you@example.com
|
|
9
|
+
# 30 2 * * * /usr/local/bin/wordmove-sync.sh
|
|
10
|
+
#
|
|
11
|
+
# Cron provides almost no environment: no rvm/rbenv shims, no ssh-agent, no TTY.
|
|
12
|
+
# This script makes ruby and the peer tools findable, relies on a key that
|
|
13
|
+
# needs no passphrase (see the docs page "Automation"), refuses to overlap
|
|
14
|
+
# with a still-running sync, and writes a plain-text log per run.
|
|
15
|
+
#
|
|
16
|
+
# Test it the way cron will run it before trusting the schedule:
|
|
17
|
+
# env -i HOME=$HOME SHELL=/bin/bash PATH=/usr/bin:/bin /usr/local/bin/wordmove-sync.sh
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# ---- settings (override with environment variables) --------------------------
|
|
21
|
+
SITE_DIR="${SITE_DIR:-/path/to/wordpress}" # directory holding movefile.yml
|
|
22
|
+
ENVIRONMENT="${ENVIRONMENT:-production}" # remote environment (-e)
|
|
23
|
+
ACTION="${ACTION:-pull}" # pull or push
|
|
24
|
+
COMPONENTS="${COMPONENTS:---all --no-db}" # component flags
|
|
25
|
+
LOG_DIR="${LOG_DIR:-$HOME/log/wordmove}"
|
|
26
|
+
KEEP_LOGS="${KEEP_LOGS:-30}" # how many run logs to keep
|
|
27
|
+
RUBY_VERSION="${RUBY_VERSION:-}" # e.g. ruby-3.4.9 for rvm; empty = whatever is on PATH
|
|
28
|
+
# -----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
case "$ACTION" in
|
|
31
|
+
pull|push) ;;
|
|
32
|
+
*) echo "ACTION must be pull or push, got '$ACTION'" >&2; exit 2 ;;
|
|
33
|
+
esac
|
|
34
|
+
|
|
35
|
+
# Ruby version managers are not loaded by cron.
|
|
36
|
+
if [ -n "$RUBY_VERSION" ] && [ -s "$HOME/.rvm/scripts/rvm" ]; then
|
|
37
|
+
# shellcheck disable=SC1091
|
|
38
|
+
source "$HOME/.rvm/scripts/rvm"
|
|
39
|
+
rvm use "$RUBY_VERSION" >/dev/null
|
|
40
|
+
elif [ -d "$HOME/.rbenv/shims" ]; then
|
|
41
|
+
export PATH="$HOME/.rbenv/shims:$PATH"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Peer tools wordmove-ng shells out to (ssh, rsync, mysqldump, wp, ...).
|
|
45
|
+
export PATH="$HOME/bin:$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
|
|
46
|
+
export LC_ALL="${LC_ALL:-C.UTF-8}"
|
|
47
|
+
|
|
48
|
+
command -v wordmove-ng >/dev/null || { echo "wordmove-ng not found in PATH" >&2; exit 2; }
|
|
49
|
+
|
|
50
|
+
mkdir -p "$LOG_DIR"
|
|
51
|
+
LOG="$LOG_DIR/${ENVIRONMENT}-$(date +%Y%m%d-%H%M%S).log"
|
|
52
|
+
LOCK_FILE="${LOCK_FILE:-${TMPDIR:-/tmp}/wordmove-${ENVIRONMENT}.lock}"
|
|
53
|
+
|
|
54
|
+
cd "$SITE_DIR"
|
|
55
|
+
|
|
56
|
+
# Refuse to start while a previous run is still active.
|
|
57
|
+
exec 9>"$LOCK_FILE"
|
|
58
|
+
if ! flock -n 9; then
|
|
59
|
+
echo "$(date '+%F %T') previous run still active, skipping" >>"$LOG"
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# The output is coloured regardless of TTY; strip the escape codes for the log.
|
|
64
|
+
# shellcheck disable=SC2086 # COMPONENTS is a list of flags on purpose
|
|
65
|
+
{
|
|
66
|
+
echo "== $(date '+%F %T') wordmove-ng $ACTION -e $ENVIRONMENT $COMPONENTS"
|
|
67
|
+
wordmove-ng "$ACTION" -e "$ENVIRONMENT" $COMPONENTS
|
|
68
|
+
echo "== $(date '+%F %T') finished, exit 0"
|
|
69
|
+
} 2>&1 | sed 's/\x1b\[[0-9;]*m//g' >>"$LOG"
|
|
70
|
+
|
|
71
|
+
# Rotate logs: keep the newest KEEP_LOGS files for this environment.
|
|
72
|
+
find "$LOG_DIR" -maxdepth 1 -name "${ENVIRONMENT}-*.log" -printf '%T@ %p\n' \
|
|
73
|
+
| sort -rn | tail -n +"$((KEEP_LOGS + 1))" | cut -d' ' -f2- | xargs -r rm -f
|
data/docs/automation.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Automation and cron
|
|
3
|
+
nav_order: 10
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Automation and cron
|
|
7
|
+
{: .no_toc }
|
|
8
|
+
|
|
9
|
+
wordmove-ng never prompts, so it runs unattended: from cron, systemd timers, CI runners or deploy scripts. What differs from an interactive shell is the environment, and this page covers exactly that.
|
|
10
|
+
|
|
11
|
+
1. TOC
|
|
12
|
+
{:toc}
|
|
13
|
+
|
|
14
|
+
## What cron does not give you
|
|
15
|
+
|
|
16
|
+
- **No version manager.** rvm and rbenv shims are loaded by your shell profile, which cron does not read. `ruby`, `gem` executables and the gemset must be made visible explicitly.
|
|
17
|
+
- **No ssh-agent.** There is no agent socket, so the SSH key must be usable without one: a key without a passphrase, or a key held by a system agent you start yourself.
|
|
18
|
+
- **A minimal `PATH`.** `rsync`, `mysqldump`, `wp` and friends installed under `~/bin`, `/usr/local/bin` or a MAMP/Local directory are not found unless you add them.
|
|
19
|
+
- **No TTY.** Output is still coloured; strip the escape codes when logging to a file.
|
|
20
|
+
|
|
21
|
+
`wordmove-ng` itself is already safe here: SSH runs with `BatchMode=yes`, a failing key authentication is an error rather than a hanging prompt, prerequisites are checked before any side effect, and every failure exits non-zero.
|
|
22
|
+
|
|
23
|
+
## Prepare once
|
|
24
|
+
|
|
25
|
+
### A key cron can use
|
|
26
|
+
{: .no_toc }
|
|
27
|
+
|
|
28
|
+
Create a dedicated key without a passphrase and restrict what it can do on the server:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ssh-keygen -t ed25519 -N '' -f ~/.ssh/wordmove_cron_ed25519 -C wordmove-cron
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
In the remote `~/.ssh/authorized_keys`, prefix the public key with restrictions:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
from="203.0.113.10",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA… wordmove-cron
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then point the movefile at a `~/.ssh/config` entry that names the key, so the movefile stays free of machine-specific paths:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Host prod-wordmove
|
|
44
|
+
Hostname example.com
|
|
45
|
+
User deploy
|
|
46
|
+
IdentityFile ~/.ssh/wordmove_cron_ed25519
|
|
47
|
+
IdentitiesOnly yes
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
production:
|
|
52
|
+
ssh:
|
|
53
|
+
host: prod-wordmove
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Secrets in `.env`
|
|
57
|
+
{: .no_toc }
|
|
58
|
+
|
|
59
|
+
Keep database passwords in a `.env` file next to `movefile.yml` with mode `600`, referenced as `<%= ENV['PROD_DB_PASS'] %>`. Never put them in the crontab, which is readable by other means and shows up in logs.
|
|
60
|
+
|
|
61
|
+
### Guard rails in the movefile
|
|
62
|
+
{: .no_toc }
|
|
63
|
+
|
|
64
|
+
A scheduled job should not be able to do more than it was written for, even if the script is edited later. Use `forbid`:
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
production:
|
|
68
|
+
forbid:
|
|
69
|
+
push:
|
|
70
|
+
db: true # a file-sync job must never push the database
|
|
71
|
+
uploads: true
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
and `exclude` for anything that lives on one side only, because syncs **mirror** the source: a scheduled `pull --all` overwrites local changes, a scheduled `push --all` overwrites uploads added through the WordPress admin since the last run.
|
|
75
|
+
|
|
76
|
+
## The script
|
|
77
|
+
|
|
78
|
+
The repository ships [`contrib/wordmove-sync.sh`](https://github.com/tekgnosis-net/wordmove-ng/blob/master/contrib/wordmove-sync.sh). Copy it to `/usr/local/bin/`, adjust the settings block at the top or override the variables from the environment. It
|
|
79
|
+
|
|
80
|
+
- loads rvm (`RUBY_VERSION=ruby-3.4.9`) or rbenv, and extends `PATH` for the peer tools;
|
|
81
|
+
- refuses to start while a previous run holds the lock, so overlapping runs cannot happen;
|
|
82
|
+
- writes one plain-text log per run to `~/log/wordmove/` with colour codes stripped, and keeps the last 30;
|
|
83
|
+
- exits non-zero when the sync fails, so cron mails you when `MAILTO` is set.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
#!/usr/bin/env bash
|
|
87
|
+
set -euo pipefail
|
|
88
|
+
|
|
89
|
+
SITE_DIR="${SITE_DIR:-/path/to/wordpress}" # directory holding movefile.yml
|
|
90
|
+
ENVIRONMENT="${ENVIRONMENT:-production}"
|
|
91
|
+
ACTION="${ACTION:-pull}" # pull or push
|
|
92
|
+
COMPONENTS="${COMPONENTS:---all --no-db}"
|
|
93
|
+
LOG_DIR="${LOG_DIR:-$HOME/log/wordmove}"
|
|
94
|
+
RUBY_VERSION="${RUBY_VERSION:-}" # e.g. ruby-3.4.9 for rvm
|
|
95
|
+
|
|
96
|
+
if [ -n "$RUBY_VERSION" ] && [ -s "$HOME/.rvm/scripts/rvm" ]; then
|
|
97
|
+
source "$HOME/.rvm/scripts/rvm"; rvm use "$RUBY_VERSION" >/dev/null
|
|
98
|
+
elif [ -d "$HOME/.rbenv/shims" ]; then
|
|
99
|
+
export PATH="$HOME/.rbenv/shims:$PATH"
|
|
100
|
+
fi
|
|
101
|
+
export PATH="$HOME/bin:$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
|
|
102
|
+
|
|
103
|
+
mkdir -p "$LOG_DIR"
|
|
104
|
+
LOG="$LOG_DIR/${ENVIRONMENT}-$(date +%Y%m%d-%H%M%S).log"
|
|
105
|
+
cd "$SITE_DIR"
|
|
106
|
+
|
|
107
|
+
exec 9>"/tmp/wordmove-${ENVIRONMENT}.lock"
|
|
108
|
+
flock -n 9 || { echo "$(date '+%F %T') previous run still active" >>"$LOG"; exit 0; }
|
|
109
|
+
|
|
110
|
+
{
|
|
111
|
+
echo "== $(date '+%F %T') wordmove-ng $ACTION -e $ENVIRONMENT $COMPONENTS"
|
|
112
|
+
wordmove-ng "$ACTION" -e "$ENVIRONMENT" $COMPONENTS
|
|
113
|
+
echo "== $(date '+%F %T') finished"
|
|
114
|
+
} 2>&1 | sed 's/\x1b\[[0-9;]*m//g' >>"$LOG"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
(abridged; the shipped file adds validation and log rotation)
|
|
118
|
+
|
|
119
|
+
## Crontab
|
|
120
|
+
|
|
121
|
+
Nightly at 02:30 local time, with failures mailed to you:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
MAILTO=you@example.com
|
|
125
|
+
30 2 * * * SITE_DIR=/home/me/sites/example RUBY_VERSION=ruby-3.4.9 /usr/local/bin/wordmove-sync.sh
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Several sites or environments are just several lines with different variables. Stagger them so their windows do not overlap on the same remote.
|
|
129
|
+
|
|
130
|
+
## Test it the way cron runs it
|
|
131
|
+
|
|
132
|
+
A missing `PATH` entry or an unreadable key only shows up under cron's empty environment, so reproduce that before trusting the schedule:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
env -i HOME=$HOME SHELL=/bin/bash PATH=/usr/bin:/bin \
|
|
136
|
+
SITE_DIR=/home/me/sites/example RUBY_VERSION=ruby-3.4.9 /usr/local/bin/wordmove-sync.sh
|
|
137
|
+
echo "exit $?"
|
|
138
|
+
tail -n 40 ~/log/wordmove/production-*.log
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Running `wordmove-ng doctor` under the same `env -i` prefix is the quickest check that the key and every tool resolve without an agent.
|
|
142
|
+
|
|
143
|
+
## Database jobs
|
|
144
|
+
|
|
145
|
+
For a scheduled database push enable `global.maintenance_mode` so the seconds between import and `wp search-replace` show visitors the maintenance page instead of the wrong URLs. Scheduled database pulls are the common case (a nightly copy of production for development) and need nothing special; each run leaves a `local-backup-<timestamp>.sql.gz` in `wp-content/`, so prune those occasionally.
|
|
146
|
+
|
|
147
|
+
## systemd timer instead of cron
|
|
148
|
+
|
|
149
|
+
The same script works as a `oneshot` service:
|
|
150
|
+
|
|
151
|
+
```ini
|
|
152
|
+
# ~/.config/systemd/user/wordmove-sync.service
|
|
153
|
+
[Service]
|
|
154
|
+
Type=oneshot
|
|
155
|
+
Environment=SITE_DIR=/home/me/sites/example RUBY_VERSION=ruby-3.4.9
|
|
156
|
+
ExecStart=/usr/local/bin/wordmove-sync.sh
|
|
157
|
+
|
|
158
|
+
# ~/.config/systemd/user/wordmove-sync.timer
|
|
159
|
+
[Timer]
|
|
160
|
+
OnCalendar=*-*-* 02:30:00
|
|
161
|
+
Persistent=true
|
|
162
|
+
[Install]
|
|
163
|
+
WantedBy=timers.target
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`systemctl --user enable --now wordmove-sync.timer`, and `journalctl --user -u wordmove-sync` for the output. Enable lingering (`loginctl enable-linger $USER`) so user timers run without a login session.
|
data/docs/contributing.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Contributing and releasing
|
|
3
|
-
nav_order:
|
|
3
|
+
nav_order: 12
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Contributing and releasing
|
|
@@ -38,9 +38,11 @@ Releases are automated by [release-please](https://github.com/googleapis/release
|
|
|
38
38
|
|
|
39
39
|
1. Every push to `master` updates a "release PR" that bumps the version and the changelog from the commits since the last release. release-please proposes a patch release for any Conventional Commit, `ci:` and `docs:` included, so merge the PR only when there is something worth shipping.
|
|
40
40
|
2. Merging it creates the `vX.Y.Z` tag and the GitHub release.
|
|
41
|
-
3. The `publish` job in `.github/workflows/release.yml
|
|
41
|
+
3. The tag push triggers the `publish` job in `.github/workflows/release.yml`, which re-runs the suite on the tagged commit, builds the gem, pushes it to rubygems.org and attaches the `.gem` file to the GitHub release.
|
|
42
42
|
|
|
43
|
-
Pushing a `v*` tag by hand at the head of `master`
|
|
43
|
+
Pushing a `v*` tag by hand at the head of `master` goes through the same publish job.
|
|
44
|
+
|
|
45
|
+
`master` is protected: changes land through pull requests whose `test` checks pass, and the rules apply to administrators too. release-please opens its PR with a fine-grained personal access token (secret `RELEASE_PLEASE_TOKEN`) because PRs opened with the built-in Actions token never trigger the checks.
|
|
44
46
|
|
|
45
47
|
## This documentation
|
|
46
48
|
|
data/docs/index.md
CHANGED
|
@@ -51,6 +51,7 @@ It is the maintained, independent successor of [Wordmove](https://github.com/wel
|
|
|
51
51
|
| know what each flag does | [Usage and flags]({{ site.baseurl }}/usage/) |
|
|
52
52
|
| know exactly what happens to my database | [Database sync]({{ site.baseurl }}/database-sync/) |
|
|
53
53
|
| run commands before or after a deploy | [Hooks]({{ site.baseurl }}/hooks/) |
|
|
54
|
+
| schedule syncs from cron or CI | [Automation and cron]({{ site.baseurl }}/automation/) |
|
|
54
55
|
| fix a problem | [Troubleshooting]({{ site.baseurl }}/troubleshooting/) |
|
|
55
56
|
|
|
56
57
|
## Credits
|
data/docs/installation.md
CHANGED
|
@@ -11,11 +11,124 @@ nav_order: 2
|
|
|
11
11
|
|
|
12
12
|
## Ruby
|
|
13
13
|
|
|
14
|
-
wordmove-ng needs **Ruby 3.0 or newer
|
|
14
|
+
wordmove-ng needs **Ruby 3.0 or newer** and is tested on 3.0 through 4.0. Check what you have:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
```bash
|
|
17
|
+
ruby --version
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
If that prints 3.0 or newer you can skip to [the gem](#the-gem). Otherwise pick one of the routes below. A version manager is the usual choice: it leaves the system Ruby alone (several distributions depend on it), installs gems into your home directory without `sudo`, and lets you upgrade Ruby later without touching anything else. Any current 3.x works; `3.4` is a good default and is what the project itself uses.
|
|
21
|
+
|
|
22
|
+
### Option A: your distribution's Ruby
|
|
23
|
+
{: .no_toc }
|
|
24
|
+
|
|
25
|
+
The quickest route when the packaged version is recent enough. Debian 12, Ubuntu 22.04 and later, Fedora and Arch all ship Ruby 3.x.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Debian / Ubuntu
|
|
29
|
+
sudo apt update && sudo apt install -y ruby-full build-essential
|
|
30
|
+
# Fedora
|
|
31
|
+
sudo dnf install -y ruby ruby-devel @development-tools
|
|
32
|
+
# Arch
|
|
33
|
+
sudo pacman -S ruby base-devel
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then install the gem for your user only, so no `sudo` is needed and the system stays untouched:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
gem install --user-install wordmove-ng
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`--user-install` puts executables under `~/.local/share/gem/ruby/<version>/bin` (older Rubies: `~/.gem/ruby/<version>/bin`). Add that directory to your `PATH` in `~/.bashrc` or `~/.zshrc`; `gem env` prints the exact path under `USER INSTALLATION DIRECTORY`.
|
|
43
|
+
|
|
44
|
+
### Option B: rbenv
|
|
45
|
+
{: .no_toc }
|
|
46
|
+
|
|
47
|
+
Lightweight, shell-agnostic, and packaged everywhere. `rbenv` selects a Ruby; the `ruby-build` plugin compiles one.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# macOS
|
|
51
|
+
brew install rbenv ruby-build
|
|
52
|
+
# Debian / Ubuntu (rbenv from apt is often old; the git checkout below is current)
|
|
53
|
+
sudo apt install -y git build-essential autoconf libssl-dev libyaml-dev zlib1g-dev libffi-dev libgmp-dev rustc
|
|
54
|
+
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
|
|
55
|
+
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
|
|
56
|
+
~/.rbenv/bin/rbenv init # prints the line to add to your shell profile; add it, then reopen the terminal
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
rbenv install 3.4.11 # compiles Ruby, takes a few minutes
|
|
61
|
+
rbenv global 3.4.11
|
|
62
|
+
ruby --version
|
|
63
|
+
gem install wordmove-ng
|
|
64
|
+
rbenv rehash # makes the wordmove-ng executable visible
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`rbenv install --list` shows the versions available; run `git -C ~/.rbenv/plugins/ruby-build pull` (or `brew upgrade ruby-build`) if a recent one is missing.
|
|
68
|
+
|
|
69
|
+
### Option C: RVM
|
|
70
|
+
{: .no_toc }
|
|
71
|
+
|
|
72
|
+
Heavier than rbenv but familiar to many WordPress developers, and its gemsets isolate one project's gems from another's.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gpg --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
|
|
76
|
+
\curl -sSL https://get.rvm.io | bash -s stable
|
|
77
|
+
source ~/.rvm/scripts/rvm # or reopen the terminal
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
rvm install 3.4.11
|
|
82
|
+
rvm use 3.4.11 --default
|
|
83
|
+
gem install wordmove-ng
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
RVM installs the build dependencies for you (it may ask for your `sudo` password once). To keep wordmove-ng in its own gemset: `rvm gemset create wordmove && rvm use 3.4.11@wordmove --default` before `gem install`. If you use the [cron script]({{ site.baseurl }}/automation/), set `RUBY_VERSION` to the same `ruby-3.4.11` or `ruby-3.4.11@wordmove` string.
|
|
87
|
+
|
|
88
|
+
### Option D: mise
|
|
89
|
+
{: .no_toc }
|
|
90
|
+
|
|
91
|
+
One tool for Ruby, Node, PHP and more, with a single config file per project. Good if you already manage other runtimes with it.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
curl https://mise.run | sh
|
|
95
|
+
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc # or: mise activate zsh >> ~/.zshrc
|
|
96
|
+
exec $SHELL
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
mise use --global ruby@3.4
|
|
101
|
+
ruby --version
|
|
102
|
+
gem install wordmove-ng
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
mise compiles Ruby through ruby-build as well, so on Linux install the same build packages listed under rbenv first; on macOS `brew install openssl@3 readline libyaml gmp autoconf`.
|
|
106
|
+
|
|
107
|
+
### Docker
|
|
108
|
+
{: .no_toc }
|
|
109
|
+
|
|
110
|
+
If you would rather not install Ruby at all, run wordmove-ng from the official Ruby image. Mount your site and your SSH configuration, and make sure the peer tools are installed in the container:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
docker run --rm -it \
|
|
114
|
+
-v "$PWD":/site -w /site \
|
|
115
|
+
-v "$HOME/.ssh":/root/.ssh:ro \
|
|
116
|
+
ruby:3.4 bash -c 'apt-get update -qq && apt-get install -y -qq rsync openssh-client mariadb-client >/dev/null \
|
|
117
|
+
&& gem install -q wordmove-ng && wordmove-ng doctor'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For repeated use bake that into a small Dockerfile. Note that `local` in your movefile then means "inside the container": `wordpress_path` is `/site`, and the local database must be reachable from the container (`host: host.docker.internal` on Docker Desktop, or the compose service name).
|
|
121
|
+
|
|
122
|
+
### Checking the result
|
|
123
|
+
{: .no_toc }
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
ruby --version # 3.0 or newer
|
|
127
|
+
gem --version
|
|
128
|
+
wordmove-ng --version
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
If `wordmove-ng` is not found right after installing, the executable directory is not in your `PATH` yet: open a new terminal, and for rbenv run `rbenv rehash`. `gem env` shows where executables were placed.
|
|
19
132
|
|
|
20
133
|
## The gem
|
|
21
134
|
|
data/docs/troubleshooting.md
CHANGED
data/docs/usage.md
CHANGED
|
@@ -109,6 +109,10 @@ exclude:
|
|
|
109
109
|
|
|
110
110
|
The same works for themes and any other folder.
|
|
111
111
|
|
|
112
|
+
## Running unattended
|
|
113
|
+
|
|
114
|
+
wordmove-ng never prompts, so it can run from cron, systemd timers or CI. The environment those give you is the only difference; see [Automation and cron]({{ site.baseurl }}/automation/) for a ready-made script and the SSH key setup.
|
|
115
|
+
|
|
112
116
|
## Rsync options in a continuous delivery context
|
|
113
117
|
|
|
114
118
|
The default rsync flags are `-rlpt`. On a CI runner every file is freshly checked out, so `--times` triggers a full transfer every time and `--perms` may not be what you want:
|
data/lib/wordmove/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wordmove-ng
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kumar
|
|
@@ -251,11 +251,13 @@ files:
|
|
|
251
251
|
- bin/setup
|
|
252
252
|
- bin/thor
|
|
253
253
|
- bin/wordmove-ng
|
|
254
|
+
- contrib/wordmove-sync.sh
|
|
254
255
|
- deploy/deploy.sh
|
|
255
256
|
- docs/Gemfile
|
|
256
257
|
- docs/README.md
|
|
257
258
|
- docs/_config.yml
|
|
258
259
|
- docs/assets/images/wordmove-ng.png
|
|
260
|
+
- docs/automation.md
|
|
259
261
|
- docs/configuration.md
|
|
260
262
|
- docs/contributing.md
|
|
261
263
|
- docs/database-sync.md
|