wordmove-ng 6.0.0

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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +11 -0
  4. data/.github/stale.yml +18 -0
  5. data/.github/workflows/release.yml +100 -0
  6. data/.github/workflows/ruby.yml +41 -0
  7. data/.gitignore +21 -0
  8. data/.release-please-manifest.json +3 -0
  9. data/.rspec +2 -0
  10. data/.rubocop.yml +50 -0
  11. data/.rubocop_todo.yml +89 -0
  12. data/.ruby-gemset +1 -0
  13. data/.ruby-version +1 -0
  14. data/.vscode/launch.json +73 -0
  15. data/CHANGELOG.md +78 -0
  16. data/CLAUDE.md +114 -0
  17. data/CONTRIBUTING.md +114 -0
  18. data/Gemfile +14 -0
  19. data/LICENSE +22 -0
  20. data/README.md +340 -0
  21. data/Rakefile +7 -0
  22. data/assets/images/wordmove-ng.png +0 -0
  23. data/bin/bundle +105 -0
  24. data/bin/bundler +17 -0
  25. data/bin/byebug +29 -0
  26. data/bin/coderay +29 -0
  27. data/bin/console +16 -0
  28. data/bin/htmldiff +29 -0
  29. data/bin/kwalify +29 -0
  30. data/bin/ldiff +29 -0
  31. data/bin/pry +29 -0
  32. data/bin/rake +29 -0
  33. data/bin/rspec +29 -0
  34. data/bin/rubocop +29 -0
  35. data/bin/ruby-parse +29 -0
  36. data/bin/ruby-rewrite +29 -0
  37. data/bin/rumoji +29 -0
  38. data/bin/setup +7 -0
  39. data/bin/thor +29 -0
  40. data/bin/wordmove-ng +10 -0
  41. data/deploy/deploy.sh +3 -0
  42. data/exe/wordmove-ng +6 -0
  43. data/lib/wordmove/assets/wordmove_schema_global.yml +16 -0
  44. data/lib/wordmove/assets/wordmove_schema_local.yml +31 -0
  45. data/lib/wordmove/assets/wordmove_schema_remote.yml +167 -0
  46. data/lib/wordmove/cli.rb +134 -0
  47. data/lib/wordmove/deployer/base.rb +356 -0
  48. data/lib/wordmove/deployer/ssh.rb +339 -0
  49. data/lib/wordmove/doctor/movefile.rb +112 -0
  50. data/lib/wordmove/doctor/mysql.rb +136 -0
  51. data/lib/wordmove/doctor/rsync.rb +27 -0
  52. data/lib/wordmove/doctor/ssh.rb +90 -0
  53. data/lib/wordmove/doctor/wpcli.rb +43 -0
  54. data/lib/wordmove/doctor.rb +67 -0
  55. data/lib/wordmove/environments_list.rb +68 -0
  56. data/lib/wordmove/exceptions.rb +10 -0
  57. data/lib/wordmove/generators/movefile.rb +50 -0
  58. data/lib/wordmove/generators/movefile.yml +104 -0
  59. data/lib/wordmove/generators/movefile_adapter.rb +188 -0
  60. data/lib/wordmove/guardian.rb +37 -0
  61. data/lib/wordmove/hook.rb +128 -0
  62. data/lib/wordmove/logger.rb +165 -0
  63. data/lib/wordmove/movefile.rb +129 -0
  64. data/lib/wordmove/prerequisites.rb +57 -0
  65. data/lib/wordmove/sql_adapter/wpcli.rb +72 -0
  66. data/lib/wordmove/ssh_runner.rb +110 -0
  67. data/lib/wordmove/version.rb +3 -0
  68. data/lib/wordmove/wordpress_directory/path.rb +11 -0
  69. data/lib/wordmove/wordpress_directory.rb +41 -0
  70. data/lib/wordmove-ng.rb +4 -0
  71. data/lib/wordmove.rb +51 -0
  72. data/release-please-config.json +25 -0
  73. data/wordmove-ng.gemspec +62 -0
  74. metadata +318 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4f483b0f5d6fbc250704d0f32134a73eef315ab0cc2b31d8313a1e6553ad1aaa
4
+ data.tar.gz: dfd3302b3678fac11044ea5a51405b57c4aab7369171f9d04d6b1e932476bd8a
5
+ SHA512:
6
+ metadata.gz: fdc7e665dbbe4e97cd9d58310cad0c23ca0cde8870da5470390aa4ac0e02285fa78be59676658b60a93490e86b7addc807cb9007821bd94787b2bbf843a4b9e8
7
+ data.tar.gz: e33568402ef5f6638f8fe0748d29aeedd724af84f84ea9395dd7c7b9f2d89cbc051437c5ea3cf2afe317a248cc21dee1fabfb3cc43f8d236e5506a5c74359f6c
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+
12
+ > A clear and concise description of what the bug is.
13
+
14
+ **Wordmove command**
15
+
16
+ > Command used on the CLI: (e.g.: `wordmove-ng pull --all --no-db`)
17
+
18
+ **Expected behavior**
19
+
20
+ > A clear and concise description of what you expected to happen.
21
+
22
+ **movefile.yml**
23
+
24
+ > Paste (removing personal data) the interesting part, if any, of your `movefile.yml` formatting it inside a code block with `yml` syntax and double checking the indentation.
25
+
26
+ **Exception/trace**
27
+
28
+ > Paste (removing personal data) the entire trace of error/exception you encountered, if any
29
+
30
+ **Environment (please complete the following information):**
31
+
32
+ - OS:
33
+ - Ruby: (`ruby --version`)
34
+ - wordmove-ng: (`wordmove-ng --version`)
35
+
36
+ **Doctor**
37
+
38
+ * [x] running the `wordmove-ng doctor` command returns all green
39
+
40
+ > (If it is not, report the error you got.)
@@ -0,0 +1,11 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Discussion
4
+ url: https://github.com/tekgnosis-net/wordmove-ng/discussions/new?category=general
5
+ about: Start an open discussion and ask for help
6
+ - name: Idea or feature request
7
+ url: https://github.com/tekgnosis-net/wordmove-ng/discussions/new?category=ideas
8
+ about: Propose your own ideas. We'll triage them and decide if bring them to the issue tracker
9
+ - name: Help
10
+ url: https://github.com/tekgnosis-net/wordmove-ng/discussions/new?category=q-a
11
+ about: Ask for help if you're stuck with wordmove-ng or integrating it with your workflow
data/.github/stale.yml ADDED
@@ -0,0 +1,18 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 60
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: 7
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - 💡 Feature
8
+ - 🐛 Bug
9
+ - 🏥 Triage
10
+ # Label to use when marking an issue as stale
11
+ staleLabel: status:wontfix
12
+ # Comment to post when marking an issue as stale. Set to `false` to disable
13
+ markComment: >
14
+ This issue has been automatically marked as stale because it has not had
15
+ recent activity. It will be closed if no further activity occurs. Thank you
16
+ for your contributions.
17
+ # Comment to post when closing a stale issue. Set to `false` to disable
18
+ closeComment: false
@@ -0,0 +1,100 @@
1
+ # Release automation.
2
+ #
3
+ # 1. release-please watches master. From Conventional Commits it opens (and keeps
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
+ # 2. The publish job then builds the gem and pushes it to rubygems.org with
7
+ # trusted publishing (OIDC, no API key) and attaches the .gem to the release.
8
+ #
9
+ # The publish job also runs when a v* tag is pushed by hand, which is how the
10
+ # very first release (v6.0.0) is cut.
11
+ #
12
+ # One-time setup (see README "Releasing"):
13
+ # - rubygems.org: pending trusted publisher for gem wordmove-ng, repository
14
+ # tekgnosis-net/wordmove-ng, workflow release.yml, environment release
15
+ # - GitHub: environment "release"; Actions setting "Allow GitHub Actions to
16
+ # create and approve pull requests" enabled (needed by release-please)
17
+
18
+ name: Release
19
+
20
+ on:
21
+ push:
22
+ branches: [master]
23
+ tags: ["v*"]
24
+ workflow_dispatch:
25
+
26
+ permissions:
27
+ contents: read
28
+
29
+ jobs:
30
+ release-please:
31
+ if: github.ref == 'refs/heads/master' && github.event_name != 'workflow_dispatch' || github.event_name == 'workflow_dispatch'
32
+ runs-on: ubuntu-latest
33
+ permissions:
34
+ contents: write
35
+ pull-requests: write
36
+ outputs:
37
+ release_created: ${{ steps.release.outputs.release_created }}
38
+ tag_name: ${{ steps.release.outputs.tag_name }}
39
+ steps:
40
+ - uses: googleapis/release-please-action@v4
41
+ id: release
42
+ with:
43
+ config-file: release-please-config.json
44
+ manifest-file: .release-please-manifest.json
45
+
46
+ publish:
47
+ needs: [release-please]
48
+ # Runs after release-please created a release, or on a manually pushed tag.
49
+ # The `always()` is needed because release-please is skipped on tag pushes.
50
+ if: >-
51
+ always() && (
52
+ needs.release-please.outputs.release_created == 'true' ||
53
+ startsWith(github.ref, 'refs/tags/v')
54
+ )
55
+ runs-on: ubuntu-latest
56
+ environment: release
57
+ permissions:
58
+ contents: write # upload the .gem to the GitHub release
59
+ id-token: write # rubygems.org trusted publishing
60
+ steps:
61
+ # `rake release` (run by release-gem) tags and pushes, so it needs a real
62
+ # branch checkout, not a detached tag.
63
+ - uses: actions/checkout@v5
64
+ with:
65
+ ref: master
66
+ fetch-depth: 0
67
+
68
+ - uses: ruby/setup-ruby@v1
69
+ with:
70
+ ruby-version: "3.4"
71
+ bundler-cache: true
72
+
73
+ - name: Verify the tag points at the head of master
74
+ env:
75
+ TAG: ${{ needs.release-please.outputs.tag_name || github.ref_name }}
76
+ run: |
77
+ git fetch --tags --force
78
+ tag_commit="$(git rev-parse "refs/tags/$TAG^{commit}")"
79
+ head_commit="$(git rev-parse HEAD)"
80
+ if [ "$tag_commit" != "$head_commit" ]; then
81
+ echo "::error::$TAG points at $tag_commit but master is at $head_commit; tag the head of master."
82
+ exit 1
83
+ fi
84
+ version="$(ruby -Ilib -e 'require "wordmove/version"; print Wordmove::VERSION')"
85
+ if [ "v$version" != "$TAG" ]; then
86
+ echo "::error::lib/wordmove/version.rb says $version but the tag is $TAG."
87
+ exit 1
88
+ fi
89
+
90
+ - name: Run the test suite once more on the release commit
91
+ run: bundle exec rake
92
+
93
+ - name: Build and push the gem to rubygems.org
94
+ uses: rubygems/release-gem@v1
95
+
96
+ - name: Attach the gem to the GitHub release
97
+ env:
98
+ GH_TOKEN: ${{ github.token }}
99
+ TAG: ${{ needs.release-please.outputs.tag_name || github.ref_name }}
100
+ run: gh release upload "$TAG" pkg/*.gem --clobber
@@ -0,0 +1,41 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Tests
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+ workflow_dispatch:
16
+
17
+ jobs:
18
+ test:
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ ruby-version:
24
+ - "3.0"
25
+ - "3.1"
26
+ - "3.2"
27
+ - "3.3"
28
+ - "3.4"
29
+ - "4.0"
30
+
31
+ steps:
32
+ - uses: actions/checkout@v5
33
+ - name: Set up Ruby
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{ matrix.ruby-version }}
37
+ bundler-cache: true
38
+ - name: Install dependencies
39
+ run: bundle install
40
+ - name: Run tests
41
+ run: bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ .DS_Store
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ spec/coverage
17
+ spec/examples.txt
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
21
+ .vs/
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "6.0.0"
3
+ }
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,50 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 3.0
5
+ NewCops: enable
6
+ DisplayCopNames: true
7
+ DisplayStyleGuide: true
8
+ SuggestExtensions: false
9
+ Exclude:
10
+ - 'bin/*'
11
+ - 'vendor/**/*'
12
+ - 'pkg/**/*'
13
+ - 'supertool/**/*'
14
+
15
+ Layout/LineLength:
16
+ Max: 100
17
+
18
+ Metrics/MethodLength:
19
+ Max: 20
20
+
21
+ Metrics/ClassLength:
22
+ Max: 200
23
+
24
+ Metrics/BlockLength:
25
+ Exclude:
26
+ - 'spec/**/*_spec.rb'
27
+ - 'spec/factories/*.rb'
28
+ - '*.gemspec'
29
+
30
+ Metrics/CyclomaticComplexity:
31
+ Max: 10
32
+
33
+ Metrics/PerceivedComplexity:
34
+ Max: 10
35
+
36
+ Metrics/AbcSize:
37
+ Max: 40
38
+
39
+ Style/StringLiterals:
40
+ Enabled: false
41
+
42
+ Style/Documentation:
43
+ Enabled: false
44
+
45
+ Style/FrozenStringLiteralComment:
46
+ Enabled: false
47
+
48
+ # Kept from the original config; the specs are written against STDOUT.
49
+ Style/GlobalStdStream:
50
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,89 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config --no-offense-counts --no-auto-gen-timestamp`
3
+ # using RuboCop version 1.90.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # This cop supports safe autocorrection (--autocorrect).
10
+ # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
11
+ # URISchemes: http, https
12
+ Layout/LineLength:
13
+ Exclude:
14
+ - 'lib/wordmove/deployer/base.rb'
15
+ - 'lib/wordmove/deployer/ssh.rb'
16
+ - 'lib/wordmove/movefile.rb'
17
+ - 'spec/cli_spec.rb'
18
+ - 'spec/deployer/base_spec.rb'
19
+ - 'spec/generators/movefile_adapter_spec.rb'
20
+ - 'spec/logger/logger_spec.rb'
21
+ - 'spec/prerequisites_spec.rb'
22
+ - 'spec/sql_adapter/wpcli_spec.rb'
23
+
24
+ # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
25
+ Lint/DuplicateBranch:
26
+ Exclude:
27
+ - 'spec/spec_helper.rb'
28
+
29
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
30
+ Metrics/AbcSize:
31
+ Exclude:
32
+ - 'lib/wordmove/deployer/base.rb'
33
+ - 'lib/wordmove/doctor/mysql.rb'
34
+
35
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
36
+ # AllowedMethods: refine
37
+ Metrics/BlockLength:
38
+ Max: 33
39
+
40
+ # Configuration parameters: CountComments, Max, CountAsOne.
41
+ Metrics/ClassLength:
42
+ Exclude:
43
+ - 'lib/wordmove/deployer/base.rb'
44
+ - 'lib/wordmove/deployer/ssh.rb'
45
+
46
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
47
+ Metrics/CyclomaticComplexity:
48
+ Exclude:
49
+ - 'lib/wordmove/deployer/base.rb'
50
+
51
+ # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
52
+ Metrics/MethodLength:
53
+ Exclude:
54
+ - 'lib/wordmove/deployer/base.rb'
55
+
56
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
57
+ Metrics/PerceivedComplexity:
58
+ Exclude:
59
+ - 'lib/wordmove/deployer/base.rb'
60
+
61
+ # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
62
+ # AllowedMethods: call
63
+ # WaywardPredicates: infinite?, nonzero?
64
+ Naming/PredicateMethod:
65
+ Exclude:
66
+ - 'lib/wordmove/doctor/movefile.rb'
67
+ - 'lib/wordmove/guardian.rb'
68
+
69
+ # This cop supports unsafe autocorrection (--autocorrect-all).
70
+ Style/IdenticalConditionalBranches:
71
+ Exclude:
72
+ - 'spec/spec_helper.rb'
73
+
74
+ Style/OpenStructUse:
75
+ Exclude:
76
+ - 'lib/wordmove/generators/movefile_adapter.rb'
77
+
78
+ # Configuration parameters: AllowedMethods.
79
+ # AllowedMethods: respond_to_missing?
80
+ Style/OptionalBooleanParameter:
81
+ Exclude:
82
+ - 'lib/wordmove/hook.rb'
83
+ - 'lib/wordmove/movefile.rb'
84
+
85
+ # This cop supports unsafe autocorrection (--autocorrect-all).
86
+ # Configuration parameters: Mode.
87
+ Style/StringConcatenation:
88
+ Exclude:
89
+ - 'lib/wordmove/deployer/ssh.rb'
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ wordmove-ng
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.9
@@ -0,0 +1,73 @@
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "name": "Debug Local File",
6
+ "type": "Ruby",
7
+ "request": "launch",
8
+ "cwd": "${workspaceRoot}",
9
+ "program": "${workspaceRoot}/main.rb"
10
+ },
11
+ {
12
+ "name": "Listen for rdebug-ide",
13
+ "type": "Ruby",
14
+ "request": "attach",
15
+ "cwd": "${workspaceRoot}",
16
+ "remoteHost": "127.0.0.1",
17
+ "remotePort": "1234",
18
+ "remoteWorkspaceRoot": "${workspaceRoot}"
19
+ },
20
+ {
21
+ "name": "Rails server",
22
+ "type": "Ruby",
23
+ "request": "launch",
24
+ "cwd": "${workspaceRoot}",
25
+ "program": "${workspaceRoot}/bin/rails",
26
+ "args": [
27
+ "server"
28
+ ]
29
+ },
30
+ {
31
+ "name": "RSpec - all",
32
+ "type": "Ruby",
33
+ "request": "launch",
34
+ "cwd": "${workspaceRoot}",
35
+ "program": "${workspaceRoot}/bin/rspec",
36
+ "args": [
37
+ "-I",
38
+ "${workspaceRoot}"
39
+ ]
40
+ },
41
+ {
42
+ "name": "RSpec - active spec file only",
43
+ "type": "Ruby",
44
+ "request": "launch",
45
+ "cwd": "${workspaceRoot}",
46
+ "program": "${workspaceRoot}/bin/rspec",
47
+ "args": [
48
+ "-I",
49
+ "${workspaceRoot}",
50
+ "${file}"
51
+ ]
52
+ },
53
+ {
54
+ "name": "RSpec - active test only",
55
+ "type": "Ruby",
56
+ "request": "launch",
57
+ "cwd": "${workspaceRoot}",
58
+ "program": "${workspaceRoot}/bin/rspec",
59
+ "args": [
60
+ "-I",
61
+ "${workspaceRoot}",
62
+ "${file}:${lineNumber}"
63
+ ]
64
+ },
65
+ {
66
+ "name": "Cucumber",
67
+ "type": "Ruby",
68
+ "request": "launch",
69
+ "cwd": "${workspaceRoot}",
70
+ "program": "${workspaceRoot}/bin/cucumber"
71
+ }
72
+ ]
73
+ }
data/CHANGELOG.md ADDED
@@ -0,0 +1,78 @@
1
+ # Changelog
2
+
3
+ All notable changes to wordmove-ng are documented here. The project follows
4
+ [Semantic Versioning](https://semver.org). Releases of the original Wordmove (up to 5.2.2)
5
+ are listed at https://github.com/welaika/wordmove/releases; the kokiddp fork's changes
6
+ between 5.2.2 and this project are summarised under 6.0.0.
7
+
8
+ ## 6.0.0 (unreleased)
9
+
10
+ First release as an independent project. Breaking changes are marked **breaking**.
11
+
12
+ ### Identity
13
+
14
+ - **breaking** Gem renamed to `wordmove-ng`, executable renamed to `wordmove-ng`. The Ruby
15
+ namespace stays `Wordmove`. The legacy `wordmove` gem can remain installed alongside.
16
+ - **breaking** Ruby 3.0 or newer is required. CI covers 3.0 through 4.0.
17
+ - New logo based on the original emblem and wordmark with an "ng" badge.
18
+
19
+ ### SSH transport
20
+
21
+ - Remote commands, single-file transfers, deletes and remote hooks use the system `ssh` and
22
+ `scp` binaries (`Wordmove::SshRunner`) instead of Net::SSH. Key authentication now behaves
23
+ exactly like the rsync file sync: ssh-agent, `~/.ssh/config`, RSA SHA-2 signatures and
24
+ `ProxyJump` all work. Fixes the database step prompting for a password while rsync
25
+ succeeded, caused by net-ssh 6 lacking RSA SHA-2 client authentication.
26
+ - Connections run with `BatchMode=yes` unless `ssh.password` is set (then `sshpass`). A
27
+ failed key authentication is an error with the failing command, never a prompt.
28
+ - `ssh.gateway` is passed as `ssh -J`. `gateway.password` cannot be honoured and is ignored;
29
+ doctor warns about it.
30
+ - Remote commands run through `sh -c`, so non-POSIX remote login shells (fish, csh) work.
31
+ - Removed the net-ssh OpenSSL 3 compatibility shim and the `ed25519` and `bcrypt_pbkdf`
32
+ dependencies, which are no longer needed.
33
+
34
+ ### Database sync
35
+
36
+ - **breaking** `push -d` imports the dump on the remote and runs `wp search-replace` there.
37
+ The local database is never modified during a push. WP-CLI is required on the remote.
38
+ - **breaking** FTP and SFTP support removed, together with the PHP dump/import scripts and
39
+ the regex-based dump rewriter (`sql_adapter: default`). A movefile with an `ftp` block
40
+ raises a clear error.
41
+ - `global.sql_adapter` is ignored (accepted with a warning). The `global` section is now
42
+ optional. `database.charset` removed from the schema.
43
+ - Prerequisites (`gzip`, `mysql`/`mariadb`, `mysqldump`/`mariadb-dump`, `wp`) are probed on
44
+ both sides before any backup or dump; a missing program aborts with a list.
45
+ - New `global.maintenance_mode` (or `WORDMOVE_MAINTENANCE_MODE=1`) wraps the target's
46
+ import and search-replace in `wp maintenance-mode activate`/`deactivate`, deactivating
47
+ even on failure. Default off.
48
+ - Warns when one search-replace term is a prefix of another; doctor reports it as an error.
49
+ - If the remote adaptation fails after the import, the log names the pre-import backup.
50
+ - Collations are normalised once per dump (previously twice on push).
51
+
52
+ ### Doctor
53
+
54
+ - Tests non interactive SSH authentication for every SSH environment and prints the failing
55
+ command and stderr.
56
+ - Probes each remote for `rsync`, `gzip`, `mysql`/`mariadb`, `mysqldump`/`mariadb-dump` and
57
+ `wp`.
58
+ - Reports `ftp` blocks, prefix collisions and gateway passwords.
59
+
60
+ ### Other
61
+
62
+ - `--result-file` and gzip paths are shell-escaped with Shellwords (a `"` or `$` in
63
+ `wordpress_path` no longer breaks the dump or import).
64
+ - Hook and Guardian output mask movefile secrets like the deployer log.
65
+ - Simulate mode no longer appends `--dry-run` to the shared `rsync_options` string.
66
+ - Rubocop 1.x with the pre-existing backlog grandfathered in `.rubocop_todo.yml`; the default
67
+ rake task runs specs and rubocop. Development dependencies moved to the Gemfile.
68
+
69
+ ### Inherited from the kokiddp fork (unreleased upstream changes since wordmove 5.2.2)
70
+
71
+ - Ruby 3.x and 4.0 compatibility, stdlib gems declared explicitly.
72
+ - MariaDB binaries preferred, sandbox-header stripping, `--binary-mode`,
73
+ `SET FOREIGN_KEY_CHECKS=0` and trailing `COMMIT;` on import.
74
+ - `database.socket` and `database.port`; `init` splits `DB_HOST` values with a socket or port.
75
+ - Built-in `utf8mb3` collation and charset fallbacks, overridable in the movefile.
76
+ - `wp` called with `--allow-root`; local vhost detected from `wp-config.php` or `wp option`.
77
+ - Command summaries in the log instead of full shell scripts; secrets masked.
78
+ - Paths with spaces supported throughout.
data/CLAUDE.md ADDED
@@ -0,0 +1,114 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this is
6
+
7
+ wordmove-ng is a Ruby gem / Thor CLI (executable `wordmove-ng`) that mirrors WordPress installs
8
+ (files + database) between a local checkout and remote SSH hosts described in a `movefile.yml`.
9
+ It is the independent successor of welaika/wordmove (via the kokiddp fork); the Ruby namespace is
10
+ still `Wordmove` and code lives under `lib/wordmove/`. Version lives in `lib/wordmove/version.rb`;
11
+ bumping it is a release step, not part of feature work.
12
+
13
+ ## Commands
14
+
15
+ ```bash
16
+ bundle install # deps (Gemfile.lock is gitignored)
17
+ bundle exec rake # default task = RSpec suite + rubocop (what CI runs)
18
+ bundle exec rake spec # specs only
19
+ bundle exec rspec spec/movefile_spec.rb # one file
20
+ bundle exec rspec spec/movefile_spec.rb:42 # one example by line
21
+ bundle exec rspec -e "some example description" # by description
22
+ bundle exec rake rubocop # lint (rubocop 1.x, NewCops enabled; backlog lives in .rubocop_todo.yml)
23
+ bin/wordmove-ng --version # run the CLI from source without installing
24
+ rake install # build + install the gem locally
25
+ ```
26
+
27
+ - `.rspec` already sets `--require spec_helper --color`; documentation formatter and
28
+ SimpleCov are enabled in `spec/spec_helper.rb`.
29
+ - CI (`.github/workflows/ruby.yml`) runs `bundle exec rake` on Ruby 3.0 through 4.0. Code must
30
+ run on Ruby 3.0 **and** Ruby 4 (see the `StringScanner#peep` shim in `lib/wordmove.rb` and the
31
+ explicit `ostruct`/`base64`/`mutex_m`/`logger` runtime deps in the gemspec). Local
32
+ `.ruby-version` is 3.4.9. Dev dependencies live in the Gemfile, not the gemspec.
33
+ - Fix new rubocop offences rather than adding to `.rubocop_todo.yml`; the todo file only
34
+ grandfathers the pre-6.0 backlog.
35
+ - `pry-byebug` is loaded optionally in specs; a `LoadError` there is tolerated.
36
+
37
+ ## Architecture (request flow)
38
+
39
+ `exe/wordmove` -> `Wordmove::CLI` (Thor, `lib/wordmove/cli.rb`) -> for `push`/`pull`:
40
+
41
+ 1. `Deployer::Base.deployer_for(cli_options)` builds a `Movefile`, loads dotenv, merges the
42
+ YAML options with CLI options, resolves the environment, then returns `Deployer::SSH`.
43
+ An `ftp` block raises `NoAdapterFound` with a removal message; a leftover
44
+ `global.sql_adapter` key only warns.
45
+ 2. `Hook.run(action, :before, options)` runs local/remote hooks from the movefile.
46
+ 3. `Guardian#allows(task)` checks `<env>.forbid.<push|pull>.<task>`; forbidden tasks are
47
+ logged and skipped, not raised.
48
+ 4. For each selected task (`wordpress uploads themes plugins mu_plugins languages db`) the CLI
49
+ calls `deployer.send("push_#{task}")` / `pull_…`. `--all` selects every task unless a flag is
50
+ explicitly `false`.
51
+ 5. `Hook.run(action, :after, options)`.
52
+
53
+ Key pieces:
54
+
55
+ - **`Movefile`** (`lib/wordmove/movefile.rb`): finds `{M,m}ovefile{,.yml,.yaml}` walking up
56
+ until `/` or a dir containing `wp-config.php`; evaluates ERB then `YAML.safe_load`; owns
57
+ environment selection (`-e` required when more than one remote env) and `secrets` (passwords,
58
+ hosts, vhosts, wordpress paths) that `Logger` masks in all output. Doctor validates it with
59
+ Kwalify against the three schemas in `lib/wordmove/assets/`.
60
+ - **`Deployer::Base`**: shared logic. Task methods and `local_/remote_<type>_dir` helpers are
61
+ metaprogrammed from lists; add a component by extending those lists plus the CLI's
62
+ `wordpress_options` and `WordpressDirectory::Path`. Builds `mysqldump`/`mysql` commands
63
+ (prefers `mariadb-dump`/`mariadb` when present), `Shellwords.escape`s every arg, and
64
+ rewrites `utf8mb3*` collations/charsets in dumps via `normalize_collations!`
65
+ (overridable through `global.collation_fallbacks` / `global.charset_fallbacks`).
66
+ - **`Deployer::SSH`** (the only deployer): directory sync is rsync via Photocopier; the
67
+ transfer root is always the WordPress root and per-component sync is expressed with
68
+ computed include/exclude path lists, so `exclude` entries in the movefile are always
69
+ relative to the WP root. Remote commands, single-file `scp` transfers, deletes and remote
70
+ hooks go through `Wordmove::SshRunner` (`lib/wordmove/ssh_runner.rb`), which shells out to
71
+ the system `ssh`/`scp` with `BatchMode=yes` unless `ssh.password` is set (then `sshpass`)
72
+ and wraps every remote command in `sh -c`. Do not reintroduce Net::SSH: Photocopier pins
73
+ net-ssh 6, which cannot do RSA SHA-2 auth. `-s/--simulate` becomes `rsync --dry-run` and
74
+ short-circuits DB steps.
75
+ - **DB sync** (same class): symmetric in both directions: probe prerequisites on both
76
+ sides, back up the target, dump the source, import on the target, then `wp search-replace`
77
+ for `vhost` and `wordpress_path` *on the target* (locally for pull, over SSH for push),
78
+ optionally inside `wp maintenance-mode`. The source DB is never written. Nothing rewrites
79
+ dump text apart from `normalize_collations!`.
80
+ - **`Doctor`** (`lib/wordmove/doctor/*`): `wordmove-ng doctor` validates the movefile schema
81
+ (rejecting `ftp`, reporting prefix collisions), then checks local mysql, wp-cli and rsync,
82
+ and per SSH environment: batch-mode auth, remote prerequisites via `Prerequisites`, and
83
+ gateway-password misuse.
84
+ - **`Generators::Movefile`**: `wordmove-ng init` wizard; reads `wp-config.php` and detects the
85
+ local vhost.
86
+ - **`Prerequisites`** (`lib/wordmove/prerequisites.rb`): one `sh` probe listing missing
87
+ programs; `DB_SOURCE`/`DB_TARGET`/`REMOTE_ALL` requirement sets shared by deployer and
88
+ doctor.
89
+ - **Knobs**: `global.maintenance_mode` (env override `WORDMOVE_MAINTENANCE_MODE`),
90
+ `global.collation_fallbacks`, `global.charset_fallbacks`. Add new toggles as movefile keys
91
+ with an env override and document them in README + CHANGELOG in the same commit.
92
+
93
+ ## Conventions worth knowing
94
+
95
+ - **Commit messages are Conventional Commits** (`feat:`, `fix:`, `feat!:`/`BREAKING CHANGE:`,
96
+ `docs:`, `chore:`, `ci:`, `test:`, `refactor:`). release-please derives the version bump
97
+ and CHANGELOG from them; never edit `lib/wordmove/version.rb` or `CHANGELOG.md` by hand.
98
+ Releases are published to rubygems.org by `.github/workflows/release.yml` (trusted
99
+ publishing, no secrets).
100
+
101
+ - Every shell fragment that includes user/config data goes through `Shellwords.escape`
102
+ (or `Shellwords.split` for user-supplied option strings). Secrets must never appear in
103
+ log lines except through `Logger`, which masks `Movefile#secrets`.
104
+ - Shell failures are detected via `$CHILD_STATUS.success?` and raised as
105
+ `ShellCommandError`; custom exceptions live in `lib/wordmove/exceptions.rb`.
106
+ - `simulate?` must be honoured by every new side-effecting step (log the step, then return).
107
+ - Specs stub `Wordmove::SshRunner` (instance_double), `Photocopier::SSH.new` and
108
+ `Prerequisites.missing_*` rather than touching SSH; `spec/deployer/ssh_db_spec.rb` records
109
+ every local and remote command in order and asserts on the sequence.
110
+ Movefile fixtures live in `spec/fixtures/movefiles/`; use `movefile_path_for("name")` from
111
+ `spec/support/fixture_helpers.rb`. `silence_stream` in `spec_helper.rb` quiets noisy output.
112
+ - Rubocop limits: 100-col lines, 20-line methods, ABC 40. `rubocop:disable-next` is used
113
+ sparingly around genuinely long orchestration methods (see `Hook.run`).
114
+ - The untracked `supertool/` directory is local tooling, not part of the gem.