wordmove 2.3.1 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b44325c0d09d56d3a59080721d52ef65d301116
4
- data.tar.gz: 5fbb645e7df0d2ec0b66773c0c52c5523ec25131
3
+ metadata.gz: 2b51293554be6d33b634aa494f0db0e88ea2326a
4
+ data.tar.gz: 2fcf92909bd0a02c28f2a2f641be9f0e03c585be
5
5
  SHA512:
6
- metadata.gz: 8112d61e266fb7b83227463dcd70e6160a006bbfa19cbf1405502783a7a0ddcb4ee8b4d8a28df9ee2d88cd9f93c7bdc962926e2da1296444fb7dff83b770f464
7
- data.tar.gz: 0f07783014805087b720a9b11b48fc7fda2a79e3b6ab0f8eca31ad75ac3d82f7b6d07c9434f393ab94b4b8924c16bfc38e324e3e550625afa09f24981a4bcec6
6
+ metadata.gz: 9a9d599400d09b8b0424eb1b88c01e1f68c80a4f280c304d6522d9e275aaf2ad6716eef0dd0c679a490f05490bd6e2b2daf6b09089ee02fab88445b2de4cb6a9
7
+ data.tar.gz: 450caed451d3c875f977a6aad2407e88d5cd895a8b7c3916a8e8d744f4a9cd0da2ddd775a606e96f0e49f705bdd57d5d76a5a4942bd0e82576781bf57e2bd394
data/README.mdown CHANGED
@@ -6,11 +6,14 @@ Wordmove is a gem that lets you automatically mirror local Wordpress
6
6
  installations and DB data back and forth from your local development machine to
7
7
  the remote server.
8
8
 
9
- **SSH** connections are fully supported, while [FTP support is planned to be discontinued](https://github.com/welaika/wordmove/wiki/FTP-support-disclaimer) when new features will be introduced.
9
+ Wordmove has also a neat hook system which enables you to run arbitrary commands
10
+ before and after push/pull actions. Local and remote commands are both supported, but remote
11
+ ones will be run only if using SSH protocol. Read the [dedicated wiki page](https://github.com/welaika/wordmove/wiki/Hooks) for more info.
10
12
 
11
- Think of it like Capistrano for Wordpress, complete with push/pull capabilities.
13
+ [FTP support has been discontinued](https://github.com/welaika/wordmove/wiki/FTP-support-disclaimer), thus most recent features won't work,
14
+ while base functionalities are granted.
12
15
 
13
- [![Build Status](https://travis-ci.org/welaika/wordmove.png?branch=master)](https://travis-ci.org/welaika/wordmove)
16
+ [![Build Status](https://travis-ci.org/welaika/wordmove.svg?branch=master)](https://travis-ci.org/welaika/wordmove)
14
17
  [![Slack channel](https://img.shields.io/badge/Slack-WP--Hub-blue.svg)](https://wphub-auto-invitation.herokuapp.com/)
15
18
  [![Gem Version](https://badge.fury.io/rb/wordmove.svg)](https://rubygems.org/gems/wordmove)
16
19
 
@@ -18,11 +21,11 @@ Think of it like Capistrano for Wordpress, complete with push/pull capabilities.
18
21
 
19
22
  That's easy:
20
23
 
21
- ```
22
- gem install wordmove
23
- ```
24
+ gem install wordmove
24
25
 
26
+ And to update:
25
27
 
28
+ gem update wordmove
26
29
 
27
30
  ## Peer dependencies
28
31
 
@@ -32,7 +35,7 @@ Wordmove just acts as automation glue bewtween tools you already have and love.
32
35
  | ------- | ---------------------------- | ------------------------------- |
33
36
  | rsync | Push and pull files and dirs | Yes for SSH connections |
34
37
  | mysql | Import and dump database | Yes |
35
- | wp-cli | DB adapt | Nope: experimental and optional |
38
+ | wp-cli | DB adapt | Nope (but soon will be) |
36
39
  | lftp | all | Yes, for FTP connections |
37
40
  | ssh | all | Yes, for SSH connections |
38
41
 
@@ -61,7 +64,7 @@ Move inside the Wordpress folder and use `wordmove init` to generate a new `move
61
64
 
62
65
  ## movefile.yml
63
66
 
64
- You can configure Wordmove creating a `movefile.yml`. That's just a YAML file with local and remote host infos:
67
+ You can configure Wordmove creating a `movefile.yml`. That's a YAML file with local and remote host(s) infos:
65
68
 
66
69
  ```yaml
67
70
  global:
@@ -113,11 +116,49 @@ production:
113
116
  ssh:
114
117
  host: host
115
118
  user: user
119
+
120
+ # hooks: # Remote hooks won't work with FTP
121
+ # push:
122
+ # before:
123
+ # local:
124
+ # - 'echo "Do something locally before push"'
125
+ # remote:
126
+ # - 'echo "Do something remotely before push"'
127
+ # after:
128
+ # local:
129
+ # - 'echo "Do something locally after push"'
130
+ # remote:
131
+ # - 'echo "Do something remotely after push"'
132
+ # pull:
133
+ # before:
134
+ # local:
135
+ # - 'echo "Do something locally before pull"'
136
+ # remote:
137
+ # - 'echo "Do something remotely before pull"'
138
+ # after:
139
+ # local:
140
+ # - 'echo "Do something locally after pull"'
141
+ # remote:
142
+ # - 'echo "Do something remotely after pull"'
116
143
  ```
117
144
 
118
145
  **We warmly recommend to read the wiki article [Multiple environments explained
119
146
  ](https://github.com/welaika/wordmove/wiki/Multiple-environments-explained) if you need multi-stage support, and the wiki article [Movefile configurations explained](https://github.com/welaika/wordmove/wiki/movefile.yml-configurations-explained) to understand about the supported configurations.**
120
147
 
148
+ ## Multistage
149
+
150
+ You can define multiple environments in your `movefile.yml`, such as production, staging, etc.
151
+ Use `-e` with `pull` or `push` to run the command on the specified environment.
152
+
153
+ For example:
154
+
155
+ wordmove push -e staging -d
156
+
157
+ will push your local database to the staging environment only.
158
+
159
+ We warmly **recommend** to read the wiki article: [Multiple environments explained
160
+ ](https://github.com/welaika/wordmove/wiki/Multiple-environments-explained)
161
+
121
162
  ## Supports
122
163
 
123
164
  ### OS
@@ -141,21 +182,17 @@ See the [Windows (un)support disclaimer](https://github.com/welaika/wordmove/wik
141
182
 
142
183
  FTP support is [planned to be discontinued](https://github.com/welaika/wordmove/wiki/FTP-support-disclaimer) at some point of future development.
143
184
 
144
- ### Multistage
185
+ ## Notes
145
186
 
146
- You can define multiple environments in your `movefile.yml`, such as production, staging, etc.
147
- Use `-e` with `pull` or `push` to run the command on the specified environment.
187
+ ### Mirroring
148
188
 
149
- For example:
150
- ```
151
- wordmove push -e staging -d
152
- ```
153
- will push your local database to the staging environment only.
154
-
155
- We warmly **recommend** to read the wiki article: [Multiple environments explained
156
- ](https://github.com/welaika/wordmove/wiki/Multiple-environments-explained)
189
+ Push and pull actions on files will perform a **mirror** operation. Please, keep
190
+ in mind that to mirror means to transfer new/updated files **and remove files**
191
+ from destination if not present in source.
157
192
 
158
- ## Notes
193
+ This means that if you have files/directories on your remotes which you must
194
+ preserve, you **must exclude those in your movefile.yml**, or they will be
195
+ deleted.
159
196
 
160
197
  ### How the heck you are able to sync the DB via FTP?
161
198
 
data/lib/wordmove.rb CHANGED
@@ -22,6 +22,7 @@ require 'wordmove/doctor/mysql'
22
22
  require 'wordmove/doctor/wpcli'
23
23
  require 'wordmove/doctor/rsync'
24
24
  require 'wordmove/doctor/ssh'
25
+ require 'wordmove/hook'
25
26
  require 'wordmove/logger'
26
27
  require 'wordmove/movefile'
27
28
  require 'wordmove/sql_adapter/default'
@@ -76,3 +76,56 @@ mapping:
76
76
  passive:
77
77
  type: bool
78
78
  scheme:
79
+ hooks:
80
+ type: map
81
+ mapping:
82
+ push:
83
+ type: map
84
+ mapping:
85
+ before:
86
+ type: map
87
+ mapping:
88
+ local:
89
+ type: seq
90
+ sequence:
91
+ - type: str
92
+ remote:
93
+ type: seq
94
+ sequence:
95
+ - type: str
96
+ after:
97
+ type: map
98
+ mapping:
99
+ local:
100
+ type: seq
101
+ sequence:
102
+ - type: str
103
+ remote:
104
+ type: seq
105
+ sequence:
106
+ - type: str
107
+ pull:
108
+ type: map
109
+ mapping:
110
+ before:
111
+ type: map
112
+ mapping:
113
+ local:
114
+ type: seq
115
+ sequence:
116
+ - type: str
117
+ remote:
118
+ type: seq
119
+ sequence:
120
+ - type: str
121
+ after:
122
+ type: map
123
+ mapping:
124
+ local:
125
+ type: seq
126
+ sequence:
127
+ - type: str
128
+ remote:
129
+ type: seq
130
+ sequence:
131
+ - type: str
data/lib/wordmove/cli.rb CHANGED
@@ -65,14 +65,19 @@ module Wordmove
65
65
  def pull
66
66
  ensure_wordpress_options_presence!(options)
67
67
  begin
68
- deployer = Wordmove::Deployer::Base.deployer_for(options)
68
+ deployer = Wordmove::Deployer::Base.deployer_for(options.deep_symbolize_keys)
69
69
  rescue MovefileNotFound => e
70
70
  logger.error(e.message)
71
71
  exit 1
72
72
  end
73
+
74
+ Wordmove::Hook.run(:pull, :before, options)
75
+
73
76
  handle_options(options) do |task|
74
77
  deployer.send("pull_#{task}")
75
78
  end
79
+
80
+ Wordmove::Hook.run(:pull, :after, options)
76
81
  end
77
82
 
78
83
  desc "push", "Pushes WP data from local machine to remote host"
@@ -87,9 +92,14 @@ module Wordmove
87
92
  logger.error(e.message)
88
93
  exit 1
89
94
  end
95
+
96
+ Wordmove::Hook.run(:push, :before, options)
97
+
90
98
  handle_options(options) do |task|
91
99
  deployer.send("push_#{task}")
92
100
  end
101
+
102
+ Wordmove::Hook.run(:push, :after, options)
93
103
  end
94
104
  end
95
105
  end
@@ -7,17 +7,9 @@ module Wordmove
7
7
 
8
8
  class << self
9
9
  def deployer_for(cli_options)
10
- options = fetch_movefile(cli_options[:config])
11
- available_enviroments = extract_available_envs(options)
12
- options.merge!(cli_options).deep_symbolize_keys!
13
-
14
- if available_enviroments.size > 1 && options[:environment].nil?
15
- raise(
16
- UndefinedEnvironment,
17
- "You need to specify an environment with --environment parameter"
18
- )
19
- end
20
- environment = (options[:environment] || available_enviroments.first).to_sym
10
+ movefile = Wordmove::Movefile.new(cli_options[:config])
11
+ options = movefile.fetch.merge! cli_options
12
+ environment = movefile.environment(cli_options)
21
13
 
22
14
  return FTP.new(environment, options) if options[environment][:ftp]
23
15
 
@@ -32,15 +24,6 @@ module Wordmove
32
24
  raise NoAdapterFound, "No valid adapter found."
33
25
  end
34
26
 
35
- def extract_available_envs(options)
36
- options.keys.map(&:to_sym) - %i[local global]
37
- end
38
-
39
- def fetch_movefile(name = nil, start_dir = current_dir)
40
- movefile = Wordmove::Movefile.new
41
- movefile.fetch name, start_dir
42
- end
43
-
44
27
  def current_dir
45
28
  '.'
46
29
  end
@@ -10,6 +10,8 @@ module Wordmove
10
10
  def push_db
11
11
  super
12
12
 
13
+ return true if simulate?
14
+
13
15
  local_dump_path = local_wp_content_dir.path("dump.sql")
14
16
  remote_dump_path = remote_wp_content_dir.path("dump.sql")
15
17
  local_backup_path = local_wp_content_dir.path("remote-backup-#{Time.now.to_i}.sql")
@@ -32,6 +34,9 @@ module Wordmove
32
34
 
33
35
  def pull_db
34
36
  super
37
+
38
+ return true if simulate?
39
+
35
40
  local_dump_path = local_wp_content_dir.path("dump.sql")
36
41
  local_backup_path = local_wp_content_dir.path("local-backup-#{Time.now.to_i}.sql")
37
42
 
@@ -9,6 +9,13 @@ module Wordmove
9
9
  def initialize(environment, options)
10
10
  super
11
11
  ssh_options = remote_options[:ssh]
12
+
13
+ if simulate? && ssh_options[:rsync_options]
14
+ ssh_options[:rsync_options].concat(" --dry-run")
15
+ elsif simulate?
16
+ ssh_options[:rsync_options] = "--dry-run"
17
+ end
18
+
12
19
  @copier = Photocopier::SSH.new(ssh_options).tap { |c| c.logger = logger }
13
20
 
14
21
  @local_dump_path = local_wp_content_dir.path("dump.sql")
@@ -23,6 +30,8 @@ module Wordmove
23
30
  def push_db
24
31
  super
25
32
 
33
+ return true if simulate?
34
+
26
35
  backup_remote_db!
27
36
  adapt_local_db!
28
37
  after_push_cleanup!
@@ -31,15 +40,20 @@ module Wordmove
31
40
  def pull_db
32
41
  super
33
42
 
43
+ return true if simulate?
44
+
34
45
  backup_local_db!
35
46
  adapt_remote_db!
36
47
  after_pull_cleanup!
37
48
  end
38
49
 
50
+ # In following commands, we do not guard for simulate?
51
+ # because it is handled through --dry-run rsync option.
52
+ # @see initialize
39
53
  %w[get put get_directory put_directory delete].each do |command|
40
54
  define_method "remote_#{command}" do |*args|
41
55
  logger.task_step false, "#{command}: #{args.join(' ')}"
42
- @copier.send(command, *args) unless simulate?
56
+ @copier.send(command, *args)
43
57
  end
44
58
  end
45
59
 
@@ -1,14 +1,14 @@
1
1
  module Wordmove
2
2
  class Doctor
3
3
  class Movefile
4
- MANDATORY_SECTIONS = %w[global local].freeze
4
+ MANDATORY_SECTIONS = %i[global local].freeze
5
5
  attr_reader :movefile, :contents, :root_keys
6
6
 
7
7
  def initialize(name = nil, dir = '.')
8
- @movefile = Wordmove::Movefile.new
8
+ @movefile = Wordmove::Movefile.new(name, dir)
9
9
 
10
10
  begin
11
- @contents = movefile.fetch(name, dir)
11
+ @contents = movefile.fetch
12
12
  @root_keys = contents.keys
13
13
  rescue Psych::SyntaxError
14
14
  movefile.logger.error "Your movefile is not parsable due to a syntax error"\
@@ -37,7 +37,7 @@ module Wordmove
37
37
  def validate_section(key)
38
38
  validator = validator_for(key)
39
39
 
40
- errors = validator.validate(contents[key])
40
+ errors = validator.validate(contents[key].deep_stringify_keys)
41
41
 
42
42
  if errors&.empty?
43
43
  movefile.logger.success "Formal validation passed"
@@ -67,7 +67,7 @@ module Wordmove
67
67
  end
68
68
 
69
69
  def validate_protocol_presence(keys)
70
- return true if keys.include?('ssh') || keys.include?('ftp')
70
+ return true if keys.include?(:ssh) || keys.include?(:ftp)
71
71
 
72
72
  movefile.logger.error "This remote has not ssh nor ftp protocol defined"
73
73
 
@@ -6,7 +6,7 @@ module Wordmove
6
6
  def initialize(movefile_name = nil, movefile_dir = '.')
7
7
  @logger = Logger.new(STDOUT).tap { |l| l.level = Logger::INFO }
8
8
  begin
9
- @config = Wordmove::Movefile.new.fetch(movefile_name, movefile_dir)["local"]["database"]
9
+ @config = Wordmove::Movefile.new(movefile_name, movefile_dir).fetch[:local][:database]
10
10
  rescue Psych::SyntaxError
11
11
  return
12
12
  end
@@ -24,19 +24,20 @@ production:
24
24
  # mysqldump_options: --max_allowed_packet=1G # Only available if using SSH
25
25
 
26
26
  exclude:
27
- - .git/
28
- - .gitignore
29
- - .sass-cache/
30
- - node_modules/
31
- - bin/
32
- - tmp/*
33
- - Gemfile*
34
- - Movefile
35
- - movefile
36
- - movefile.yml
37
- - movefile.yaml
38
- - wp-config.php
39
- - wp-content/*.sql.gz
27
+ - '.git/'
28
+ - '.gitignore'
29
+ - '.sass-cache/'
30
+ - 'node_modules/'
31
+ - 'bin/'
32
+ - 'tmp/*'
33
+ - 'Gemfile*'
34
+ - 'Movefile'
35
+ - 'movefile'
36
+ - 'movefile.yml'
37
+ - 'movefile.yaml'
38
+ - 'wp-config.php'
39
+ - 'wp-content/*.sql.gz'
40
+ - '*.orig'
40
41
 
41
42
  # paths: # you can customize wordpress internal paths
42
43
  # wp_content: wp-content
@@ -51,7 +52,7 @@ production:
51
52
  # user: user
52
53
  # password: password # password is optional, will use public keys if available.
53
54
  # port: 22 # Port is optional
54
- # rsync_options: --verbose # Additional rsync options, optional
55
+ # rsync_options: --verbose --itemize-changes# Additional rsync options, optional
55
56
  # gateway: # Gateway is optional
56
57
  # host: host
57
58
  # user: user
@@ -64,5 +65,29 @@ production:
64
65
  # passive: true
65
66
  # scheme: ftps # default ftp
66
67
 
68
+ # hooks: # Remote hooks won't work with FTP
69
+ # push:
70
+ # before:
71
+ # local:
72
+ # - 'echo "Do something locally before push"'
73
+ # remote:
74
+ # - 'echo "Do something remotely before push"'
75
+ # after:
76
+ # local:
77
+ # - 'echo "Do something locally after push"'
78
+ # remote:
79
+ # - 'echo "Do something remotely after push"'
80
+ # pull:
81
+ # before:
82
+ # local:
83
+ # - 'echo "Do something locally before pull"'
84
+ # remote:
85
+ # - 'echo "Do something remotely before pull"'
86
+ # after:
87
+ # local:
88
+ # - 'echo "Do something locally after pull"'
89
+ # remote:
90
+ # - 'echo "Do something remotely after pull"'
91
+
67
92
  # staging: # multiple environments can be specified
68
93
  # [...]
@@ -0,0 +1,114 @@
1
+ module Wordmove
2
+ class Hook
3
+ def self.logger
4
+ Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
5
+ end
6
+
7
+ def self.run(action, step, cli_options)
8
+ movefile = Wordmove::Movefile.new(cli_options[:config])
9
+ options = movefile.fetch(false)
10
+ environment = movefile.environment(cli_options)
11
+
12
+ hooks = Wordmove::Hook::Config.new(
13
+ options[environment][:hooks],
14
+ action,
15
+ step
16
+ )
17
+
18
+ unless hooks.local_hooks.empty?
19
+ Wordmove::Hook::Local.run(hooks.local_hooks, cli_options[:simulate])
20
+ end
21
+
22
+ return if hooks.remote_hooks.empty?
23
+
24
+ if options[environment][:ftp]
25
+ logger.debug "You have configured remote hooks to run over "\
26
+ "an FTP connections, but this is not possible. Skipping."
27
+
28
+ return
29
+ end
30
+
31
+ Wordmove::Hook::Remote.run(
32
+ hooks.remote_hooks, options[environment][:ssh], cli_options[:simulate]
33
+ )
34
+ end
35
+
36
+ Config = Struct.new(:options, :action, :step) do
37
+ def empty?
38
+ (local_hooks + remote_hooks).empty?
39
+ end
40
+
41
+ def local_hooks
42
+ return [] if empty_step?
43
+
44
+ options[action][step][:local] || []
45
+ end
46
+
47
+ def remote_hooks
48
+ return [] if empty_step?
49
+
50
+ options[action][step][:remote] || []
51
+ end
52
+
53
+ private
54
+
55
+ def empty_step?
56
+ return true unless options
57
+ return true if options[action].nil?
58
+ return true if options[action][step].nil?
59
+
60
+ false
61
+ end
62
+ end
63
+
64
+ class Local
65
+ def self.logger
66
+ parent.logger
67
+ end
68
+
69
+ def self.run(commands, simulate = false)
70
+ logger.task "Running local hooks"
71
+
72
+ commands.each do |command|
73
+ logger.task_step true, "Exec command: #{command}"
74
+ return true if simulate
75
+
76
+ stdout_return = `#{command} 2>&1`
77
+ logger.task_step true, "Output: #{stdout_return}"
78
+
79
+ if $CHILD_STATUS.exitstatus.zero?
80
+ logger.success ""
81
+ else
82
+ logger.error "Error code: #{$CHILD_STATUS.exitstatus}"
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ class Remote
89
+ def self.logger
90
+ parent.logger
91
+ end
92
+
93
+ def self.run(commands, ssh_options, simulate = false)
94
+ logger.task "Running remote hooks"
95
+
96
+ copier = Photocopier::SSH.new(ssh_options).tap { |c| c.logger = logger }
97
+ commands.each do |command|
98
+ logger.task_step false, "Exec command: #{command}"
99
+ return true if simulate
100
+
101
+ stdout, stderr, exit_code = copier.exec! command
102
+
103
+ if exit_code.zero?
104
+ logger.task_step false, "Output: #{stdout}"
105
+ logger.success ""
106
+ else
107
+ logger.task_step false, "Output: #{stderr}"
108
+ logger.error "Error code #{exit_code}"
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -1,12 +1,14 @@
1
1
  module Wordmove
2
2
  class Movefile
3
- attr_reader :logger
3
+ attr_reader :logger, :name, :start_dir
4
4
 
5
- def initialize
5
+ def initialize(name = nil, start_dir = current_dir)
6
6
  @logger = Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
7
+ @name = name
8
+ @start_dir = start_dir
7
9
  end
8
10
 
9
- def fetch(name = nil, start_dir = current_dir)
11
+ def fetch(verbose = true)
10
12
  entries = if name.nil?
11
13
  Dir["#{File.join(start_dir, '{M,m}ovefile')}{,.yml,.yaml}"]
12
14
  else
@@ -15,16 +17,36 @@ module Wordmove
15
17
 
16
18
  if entries.empty?
17
19
  raise MovefileNotFound, "Could not find a valid Movefile" if last_dir?(start_dir)
18
- return fetch(name, upper_dir(start_dir))
20
+ @start_dir = upper_dir(start_dir)
21
+ return fetch
19
22
  end
20
23
 
21
24
  found = entries.first
22
- logger.task("Using Movefile: #{found}")
23
- YAML.safe_load(ERB.new(File.read(found)).result, [], [], true)
25
+ logger.task("Using Movefile: #{found}") if verbose == true
26
+ YAML.safe_load(ERB.new(File.read(found)).result, [], [], true).deep_symbolize_keys!
27
+ end
28
+
29
+ def environment(cli_options = {})
30
+ options = fetch(false)
31
+ available_enviroments = extract_available_envs(options)
32
+ options.merge!(cli_options).deep_symbolize_keys!
33
+
34
+ if available_enviroments.size > 1 && options[:environment].nil?
35
+ raise(
36
+ UndefinedEnvironment,
37
+ "You need to specify an environment with --environment parameter"
38
+ )
39
+ end
40
+
41
+ (options[:environment] || available_enviroments.first).to_sym
24
42
  end
25
43
 
26
44
  private
27
45
 
46
+ def extract_available_envs(options)
47
+ options.keys.map(&:to_sym) - %i[local global]
48
+ end
49
+
28
50
  def last_dir?(directory)
29
51
  directory == "/" || File.exist?(File.join(directory, 'wp-config.php'))
30
52
  end
@@ -1,3 +1,3 @@
1
1
  module Wordmove
2
- VERSION = "2.3.1".freeze
2
+ VERSION = "2.4.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wordmove
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefano Verna
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: exe
14
14
  cert_chain: []
15
- date: 2017-12-23 00:00:00.000000000 Z
15
+ date: 2017-12-28 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activesupport
@@ -264,6 +264,7 @@ files:
264
264
  - lib/wordmove/generators/movefile.rb
265
265
  - lib/wordmove/generators/movefile.yml
266
266
  - lib/wordmove/generators/movefile_adapter.rb
267
+ - lib/wordmove/hook.rb
267
268
  - lib/wordmove/logger.rb
268
269
  - lib/wordmove/movefile.rb
269
270
  - lib/wordmove/sql_adapter/default.rb