Skip to content

Commit 4b80f38

Browse files
authored
Merge pull request #126 from harawata/new-hooks
Add before/after-new hooks.
2 parents 6007324 + a8dd39c commit 4b80f38

File tree

8 files changed

+278
-22
lines changed

8 files changed

+278
-22
lines changed

src/main/java/org/apache/ibatis/migration/Environment.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2010-2017 the original author or authors.
2+
* Copyright 2010-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,7 +52,9 @@ private enum SETTING_KEY {
5252
hook_before_down,
5353
hook_before_each_down,
5454
hook_after_each_down,
55-
hook_after_down
55+
hook_after_down,
56+
hook_before_new,
57+
hook_after_new
5658
}
5759

5860
private static final List<String> SETTING_KEYS;
@@ -89,6 +91,9 @@ private enum SETTING_KEY {
8991
private final String hookAfterEachDown;
9092
private final String hookAfterDown;
9193

94+
private final String hookBeforeNew;
95+
private final String hookAfterNew;
96+
9297
private final Properties variables = new Properties();
9398

9499
public Environment(File file) {
@@ -122,6 +127,9 @@ public Environment(File file) {
122127
this.hookAfterEachDown = prop.getProperty(SETTING_KEY.hook_after_each_down.name());
123128
this.hookAfterDown = prop.getProperty(SETTING_KEY.hook_after_down.name());
124129

130+
this.hookBeforeNew = prop.getProperty(SETTING_KEY.hook_before_new.name());
131+
this.hookAfterNew = prop.getProperty(SETTING_KEY.hook_after_new.name());
132+
125133
// User defined variables.
126134
Set<Entry<Object, Object>> entries = prop.entrySet();
127135
for (Entry<Object, Object> entry : entries) {
@@ -229,6 +237,14 @@ public String getHookAfterDown() {
229237
return hookAfterDown;
230238
}
231239

240+
public String getHookBeforeNew() {
241+
return hookBeforeNew;
242+
}
243+
244+
public String getHookAfterNew() {
245+
return hookAfterNew;
246+
}
247+
232248
public Properties getVariables() {
233249
return variables;
234250
}

src/main/java/org/apache/ibatis/migration/commands/NewCommand.java

+24
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
package org.apache.ibatis.migration.commands;
1717

1818
import java.io.File;
19+
import java.util.HashMap;
20+
import java.util.Map;
1921
import java.util.Properties;
2022

2123
import org.apache.ibatis.migration.MigrationException;
24+
import org.apache.ibatis.migration.hook.MigrationHook;
25+
import org.apache.ibatis.migration.hook.NewHookContext;
2226
import org.apache.ibatis.migration.options.SelectedOptions;
2327
import org.apache.ibatis.migration.utils.Util;
2428

@@ -41,6 +45,13 @@ public void execute(String... params) {
4145
existingEnvironmentFile();
4246
String filename = getNextIDAsString() + "_" + description.replace(' ', '_') + ".sql";
4347

48+
Map<String, Object> hookBindings = new HashMap<String, Object>();
49+
MigrationHook hook = createNewHook();
50+
if (hook != null) {
51+
hookBindings.put(MigrationHook.HOOK_CONTEXT, new NewHookContext(description, filename));
52+
hook.before(hookBindings);
53+
}
54+
4455
if (options.getTemplate() != null) {
4556
copyExternalResourceTo(options.getTemplate(), Util.file(paths.getScriptPath(), filename), variables);
4657
} else {
@@ -53,6 +64,10 @@ public void execute(String... params) {
5364
.append("Your migrations configuration did not find your custom template. Using the default template.");
5465
copyDefaultTemplate(variables, filename);
5566
}
67+
if (hook != null) {
68+
hookBindings.put(MigrationHook.HOOK_CONTEXT, new NewHookContext(description, filename));
69+
hook.after(hookBindings);
70+
}
5671
}
5772
printStream.println("Done!");
5873
printStream.println();
@@ -62,4 +77,13 @@ private void copyDefaultTemplate(Properties variables, String filename) {
6277
copyResourceTo("org/apache/ibatis/migration/template_migration.sql", Util.file(paths.getScriptPath(), filename),
6378
variables);
6479
}
80+
81+
private MigrationHook createNewHook() {
82+
String before = environment().getHookBeforeNew();
83+
String after = environment().getHookAfterNew();
84+
if (before == null && after == null) {
85+
return null;
86+
}
87+
return createFileMigrationHook(before, null, null, after);
88+
}
6589
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright 2010-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.migration.hook;
17+
18+
/**
19+
* Hook context object that is available to <code>before_new</code> and <code>after_new</code> hooks.
20+
*/
21+
public class NewHookContext {
22+
private String description;
23+
private String filename;
24+
25+
public NewHookContext(String description, String filename) {
26+
super();
27+
this.description = description;
28+
this.filename = filename;
29+
}
30+
31+
/**
32+
* @return The specified description.
33+
*/
34+
public String getDescription() {
35+
return description;
36+
}
37+
38+
/**
39+
* @return The name of the file that is created by new command.<br>
40+
* In <code>before_new</code> hook, the file is not created yet.
41+
*/
42+
public String getFilename() {
43+
return filename;
44+
}
45+
}

src/site/xdoc/hooks.xml

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
4-
Copyright 2010-2016 the original author or authors.
4+
Copyright 2010-2018 the original author or authors.
55
66
Licensed under the Apache License, Version 2.0 (the "License");
77
you may not use this file except in compliance with the License.
@@ -127,6 +127,8 @@ Hello, World!]]></source>
127127
<li>hook_before_each_down</li>
128128
<li>hook_after_each_down</li>
129129
<li>hook_after_down</li>
130+
<li>hook_before_new (since 3.3.5)</li>
131+
<li>hook_after_new (since 3.3.5)</li>
130132
</ul>
131133

132134
<h4>Minimum setting : language and file name</h4>
@@ -200,6 +202,17 @@ print(migrationPaths.getScriptPath());
200202
print(migrationPaths.getDriverPath());
201203
print(migrationPaths.getHookPath());]]></source>
202204

205+
<h4>About <i>hookContext</i></h4>
206+
207+
<p>
208+
A global variable <code>hookContext</code> is passed to each hook script, but the object bound to this variable depends on the hook.
209+
</p>
210+
211+
<ul>
212+
<li>For hooks except before_new and after_new, it is an instance of <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/HookContext.html" target="_blank">HookContext</a>.</li>
213+
<li>For before_new and after_new hooks, it will be <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/NewHookContext.html" target="_blank">NewHookContext</a>.</li>
214+
</ul>
215+
203216
<h4>Accessing <i>Change</i> object (in each hook only)</h4>
204217

205218
<p>
@@ -214,6 +227,11 @@ print(hookContext.getChange().getFilename());]]></source>
214227
The Change instance is a clone and will be discarded after each exection, so modifying it would be meaningless.
215228
</p>
216229

230+
<p>
231+
<span class="label important">NOTE</span>
232+
Change is not available to before_new and after_new hooks.
233+
</p>
234+
217235
<h4>Execute SQL statement</h4>
218236

219237
<p>
@@ -240,6 +258,10 @@ try {
240258
stmt = null;
241259
}]]></source>
242260

261+
<p>
262+
<span class="label important">NOTE</span>
263+
These methods are not available to before_new and after_new hooks.
264+
</p>
243265

244266
<h4>Invoking function</h4>
245267

src/test/java/org/apache/ibatis/migration/MigratorTest.java

+8-18
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public void checkAssertion() {
297297

298298
@Test
299299
public void shouldInitTempDirectory() throws Exception {
300-
File basePath = getTempDir();
300+
File basePath = TestUtil.getTempDir();
301301
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
302302
assertNotNull(basePath.list());
303303
assertEquals(4, basePath.list().length);
@@ -310,7 +310,7 @@ public void shouldInitTempDirectory() throws Exception {
310310
@Test
311311
public void shouldRespectIdPattern() throws Exception {
312312
String idPattern = "000";
313-
File basePath = getTempDir();
313+
File basePath = TestUtil.getTempDir();
314314
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--idpattern=" + idPattern, "init"));
315315
File changelog = new File(
316316
basePath.getCanonicalPath() + File.separator + "scripts" + File.separator + "001_create_changelog.sql");
@@ -325,7 +325,7 @@ public void shouldRespectIdPattern() throws Exception {
325325
@Test
326326
public void useCustomTemplate() throws Exception {
327327
String desc = "test new migration";
328-
File basePath = getTempDir();
328+
File basePath = TestUtil.getTempDir();
329329
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
330330
assertNotNull(basePath.list());
331331
assertEquals(4, basePath.list().length);
@@ -351,7 +351,7 @@ public void useCustomTemplate() throws Exception {
351351

352352
@Test
353353
public void useCustomTemplateWithNoValue() throws Exception {
354-
File basePath = getTempDir();
354+
File basePath = TestUtil.getTempDir();
355355
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
356356
assertNotNull(basePath.list());
357357
assertEquals(4, basePath.list().length);
@@ -368,7 +368,7 @@ public void useCustomTemplateWithNoValue() throws Exception {
368368
@Test
369369
public void useCustomTemplateWithBadPath() throws Exception {
370370
System.setProperty("migrationsHome", "/tmp");
371-
File basePath = getTempDir();
371+
File basePath = TestUtil.getTempDir();
372372
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
373373
assertNotNull(basePath.list());
374374
assertEquals(4, basePath.list().length);
@@ -386,7 +386,7 @@ public void useCustomTemplateWithBadPath() throws Exception {
386386
@Test
387387
public void shouldSuppressOutputIfQuietOptionEnabled() throws Throwable {
388388
System.setProperty("migrationsHome", "/tmp");
389-
File basePath = getTempDir();
389+
File basePath = TestUtil.getTempDir();
390390
out.clearLog();
391391
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--quiet", "init"));
392392
String output = out.getLog();
@@ -397,7 +397,7 @@ public void shouldSuppressOutputIfQuietOptionEnabled() throws Throwable {
397397
@Test
398398
public void shouldColorizeSuccessOutputIfColorOptionEnabled() throws Throwable {
399399
System.setProperty("migrationsHome", "/tmp");
400-
File basePath = getTempDir();
400+
File basePath = TestUtil.getTempDir();
401401
out.clearLog();
402402
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--color", "init"));
403403
String output = out.getLog();
@@ -415,18 +415,8 @@ public void checkAssertion() {
415415
}
416416
});
417417
System.setProperty("migrationsHome", "/tmp");
418-
File basePath = getTempDir();
418+
File basePath = TestUtil.getTempDir();
419419
out.clearLog();
420420
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--color", "new"));
421421
}
422-
423-
private File getTempDir() throws IOException {
424-
File f = File.createTempFile("migration", "test");
425-
assertTrue(f.delete());
426-
assertTrue(f.mkdir());
427-
assertTrue(f.exists());
428-
assertTrue(f.isDirectory());
429-
f.deleteOnExit();
430-
return f;
431-
}
432422
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright 2010-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.migration.hook;
17+
18+
import static org.junit.Assert.*;
19+
20+
import java.io.BufferedWriter;
21+
import java.io.File;
22+
import java.io.FileInputStream;
23+
import java.io.FileOutputStream;
24+
import java.io.IOException;
25+
import java.io.OutputStreamWriter;
26+
import java.io.PrintWriter;
27+
import java.nio.channels.FileChannel;
28+
29+
import org.apache.ibatis.io.Resources;
30+
import org.apache.ibatis.migration.Migrator;
31+
import org.apache.ibatis.migration.utils.TestUtil;
32+
import org.apache.ibatis.migration.utils.Util;
33+
import org.junit.Rule;
34+
import org.junit.Test;
35+
import org.junit.contrib.java.lang.system.Assertion;
36+
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
37+
import org.junit.contrib.java.lang.system.SystemOutRule;
38+
39+
public class NewHookTest {
40+
@Rule
41+
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
42+
43+
@Rule
44+
public final SystemOutRule out = new SystemOutRule().enableLog();
45+
46+
@Test
47+
public void shouldRunNewHooks() throws Throwable {
48+
File basePath = initBaseDir();
49+
File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
50+
Migrator
51+
.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--idpattern=00", "new", "create table1 JIRA-123"));
52+
String[] scripts = scriptPath.list();
53+
assertEquals(4, scripts.length);
54+
String output = out.getLog();
55+
assertTrue(output.contains("SUCCESS"));
56+
assertTrue(output.contains("Description is valid."));
57+
assertTrue(output.contains("Renamed 03_create_table1_JIRA-123.sql to 03_create_table1_JIRA123.sql"));
58+
assertTrue(new File(scriptPath, "03_create_table1_JIRA123.sql").exists());
59+
}
60+
61+
@Test
62+
public void shouldNotCreateFileWhenBeforeHookThrowsException() throws Throwable {
63+
exit.expectSystemExitWithStatus(1);
64+
exit.checkAssertionAfterwards(new Assertion() {
65+
public void checkAssertion() {
66+
String output = out.getLog();
67+
assertTrue(output.contains("FAILURE"));
68+
}
69+
});
70+
File basePath = initBaseDir();
71+
File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
72+
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "new", "create table1"));
73+
assertEquals(3, scriptPath.list().length);
74+
}
75+
76+
protected File initBaseDir() throws IOException {
77+
File basePath = TestUtil.getTempDir();
78+
Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--idpattern=00", "init"));
79+
// Copy hook script
80+
File hooksDir = new File(basePath, "hooks");
81+
hooksDir.mkdir();
82+
FileInputStream srcStream = new FileInputStream(
83+
Resources.getResourceAsFile("org/apache/ibatis/migration/hook/testdir/hooks/NewHook.js"));
84+
FileOutputStream destStream = new FileOutputStream(Util.file(hooksDir, "NewHook.js"));
85+
try {
86+
FileChannel srcChannel = srcStream.getChannel();
87+
FileChannel destChannel = destStream.getChannel();
88+
srcChannel.transferTo(0, srcChannel.size(), destChannel);
89+
} finally {
90+
srcStream.close();
91+
destStream.close();
92+
}
93+
// Add hook settings
94+
File envFile = new File(basePath.getCanonicalPath() + File.separator + "environments", "development.properties");
95+
PrintWriter writer = new PrintWriter(
96+
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(envFile, true), "utf-8")));
97+
try {
98+
writer.println("hook_before_new=js:NewHook.js:_function=validateDesc");
99+
writer.println("hook_after_new=js:NewHook.js:_function=renameFile");
100+
} finally {
101+
writer.close();
102+
}
103+
return basePath;
104+
}
105+
}

0 commit comments

Comments
 (0)