Skip to content
Permalink
Browse files

JENKINS-23908 - created external invoker

  • Loading branch information
prospero238 committed Jul 23, 2014
1 parent 4b64c53 commit ceb9be713b1975b73451d4bf0a0ece7e19cb095d
@@ -0,0 +1,29 @@
package org.jenkinsci.plugins.liquibase.builder;

import hudson.console.LineTransformationOutputStream;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

import org.jenkinsci.plugins.liquibase.external.ChangeSetNote;

public class Annotator extends LineTransformationOutputStream {
private final OutputStream out;
private final Charset charset;

public Annotator(OutputStream out, Charset charset) {
this.out = out;
this.charset = charset;
}
@Override
protected void eol(byte[] b, int len) throws IOException {
String line = trimEOL(charset.decode(ByteBuffer.wrap(b, 0, len)).toString());

if (ChangeSetNote.doesLineHaveChangeset(line)) {
new ChangeSetNote().encodeTo(out);

}
out.write(b, 0, len);
}}
@@ -0,0 +1,60 @@
package org.jenkinsci.plugins.liquibase.builder;

import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.util.ArgumentListBuilder;

import java.io.File;
import java.io.IOException;
import java.util.Properties;

import org.jenkinsci.plugins.liquibase.installation.LiquibaseInstallation;

import com.google.common.base.Strings;

public class Invoker {

private static final String DEFAULT_LOG_LEVEL = "info";

public boolean invokeLiquibase(Properties properties,
BuildListener listener,
Launcher launcher,
AbstractBuild<?, ?> build,
LiquibaseBuilder liquibaseBuilder,
Annotator annotator) {
ArgumentListBuilder cliCommand = new ArgumentListBuilder();
String execName;
if (launcher.isUnix()) {
execName = LiquibaseInstallation.UNIX_EXEC_NAME;
} else {
execName = LiquibaseInstallation.WINDOWS_EXEC_NAME;
}


cliCommand.add(new File(liquibaseBuilder.getInstallation().getHome(), execName));
cliCommand.add("--" + LiquibaseProperty.LOG_LEVEL.getOption(), DEFAULT_LOG_LEVEL);
addOptionIfPresent(cliCommand, LiquibaseProperty.DEFAULTS_FILE, liquibaseBuilder.getLiquibasePropertiesPath());

cliCommand.add("update");

try {
launcher.launch().cmds(cliCommand).stderr(annotator).stdout(annotator).pwd(build.getWorkspace()).join();
} catch (IOException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
} catch (InterruptedException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
}
return true;

}

private static void addOptionIfPresent(ArgumentListBuilder cmdExecArgs, LiquibaseProperty liquibaseProperty, String value) {
if (!Strings.isNullOrEmpty(value)) {
cmdExecArgs.add("--" + liquibaseProperty.getOption(), value);
}
}
}
@@ -118,41 +118,47 @@ public LiquibaseBuilder(String changeLogFile,
@Override
public boolean perform(final AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {

Annotator annotator = new Annotator(listener.getLogger(), build.getCharset());
Properties configProperties = PropertiesParser.createConfigProperties(this);
ExecutedChangesetAction action = new ExecutedChangesetAction(build);

Liquibase liquibase = createLiquibase(build, listener, action, configProperties);
String liqContexts = configProperties.getProperty(LiquibaseProperty.CONTEXTS.getOption());
try {
if (testRollbacks) {
liquibase.updateTestingRollback(liqContexts);
} else {
liquibase.update(new Contexts(liqContexts));
}
build.addAction(action);
} catch (MigrationFailedException migrationException) {
Optional<ChangeSet> changeSetOptional = reflectFailed(migrationException);
if (changeSetOptional.isPresent()) {
action.addFailed(changeSetOptional.get());
}
migrationException.printStackTrace(listener.getLogger());
build.setResult(Result.UNSTABLE);
} catch (DatabaseException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
} catch (LiquibaseException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
} finally {
if (liquibase.getDatabase() != null) {
try {
liquibase.getDatabase().close();
} catch (DatabaseException e) {
LOG.warn("error closing database", e);
if (invokeExternal) {
Invoker invoker = new Invoker();
invoker.invokeLiquibase(configProperties, listener, launcher,build, this, annotator);

} else {
ExecutedChangesetAction action = new ExecutedChangesetAction(build);
Liquibase liquibase = createLiquibase(build, listener, action, configProperties);
String liqContexts = configProperties.getProperty(LiquibaseProperty.CONTEXTS.getOption());
try {
if (testRollbacks) {
liquibase.updateTestingRollback(liqContexts);
} else {
liquibase.update(new Contexts(liqContexts));
}
build.addAction(action);
} catch (MigrationFailedException migrationException) {
Optional<ChangeSet> changeSetOptional = reflectFailed(migrationException);
if (changeSetOptional.isPresent()) {
action.addFailed(changeSetOptional.get());
}
migrationException.printStackTrace(listener.getLogger());
build.setResult(Result.UNSTABLE);
} catch (DatabaseException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
} catch (LiquibaseException e) {
e.printStackTrace(listener.getLogger());
build.setResult(Result.FAILURE);
} finally {
if (liquibase.getDatabase() != null) {
try {
liquibase.getDatabase().close();
} catch (DatabaseException e) {
LOG.warn("error closing database", e);
}
}
}
}

return true;
}

@@ -237,6 +243,10 @@ public String getUsername() {
return username;
}

public void setInvokeExternal(boolean invokeExternal) {
this.invokeExternal = invokeExternal;
}

public boolean isInvokeExternal() {
return invokeExternal;
}
@@ -261,6 +271,10 @@ public String getLiquibasePropertiesPath() {
return liquibasePropertiesPath;
}

public void setLiquibasePropertiesPath(String liquibasePropertiesPath) {
this.liquibasePropertiesPath = liquibasePropertiesPath;
}

public void setChangeLogFile(String changeLogFile) {
this.changeLogFile = changeLogFile;
}
@@ -293,11 +307,33 @@ public void setDriverName(String driverName) {
this.driverName = driverName;
}

public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
public LiquibaseInstallation getInstallation() {
LiquibaseInstallation found = null;
if (installationName != null) {
for (LiquibaseInstallation i : DESCRIPTOR.getInstallations()) {
if (installationName.equals(i.getName())) {
found = i;
break;
}
}
}
return found;
}



public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
private List<EmbeddedDriver> embeddedDrivers;
private LiquibaseInstallation[] installations;

public DescriptorImpl() {
load();
}

public DescriptorImpl(Class<? extends LiquibaseBuilder> clazz) {
super(clazz);
}

@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
@@ -329,7 +365,7 @@ private void initDriverList() {
return installations;
}

public void setInstallations(LiquibaseInstallation[] installations) {
public void setInstallations(LiquibaseInstallation... installations) {
this.installations = installations;
save();
}
@@ -0,0 +1,34 @@
package org.jenkinsci.plugins.liquibase.external;

import hudson.MarkupText;
import hudson.console.ConsoleAnnotator;
import hudson.console.ConsoleNote;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* finds changeset names and marks console accordingly.
*/
public class ChangeSetNote extends ConsoleNote {
public static Pattern CHANGESET_PATTERN = Pattern.compile("(\\S+::)?(\\S+)::(\\S+): ");

@Override
public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
Matcher matcher = CHANGESET_PATTERN.matcher(text.getText());
while (matcher.find()) {
String changeSetName = matcher.group(2);
int start = matcher.start(2);
text.addMarkup(start, changeSetName.length() + start, "<b class=liquibase-changeset>", "</b>");
}

return null;
}

public static boolean doesLineHaveChangeset(String line) {
Matcher matcher = CHANGESET_PATTERN.matcher(line);
return matcher.find();
}


}
@@ -12,6 +12,7 @@
import jenkins.model.Jenkins;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;

import org.jenkinsci.plugins.liquibase.builder.LiquibaseBuilder;
@@ -21,7 +22,10 @@
* Describes details of liquibase installation.
*/
public class LiquibaseInstallation extends ToolInstallation
implements NodeSpecific<LiquibaseInstallation>, EnvironmentSpecific<LiquibaseInstallation> {
implements NodeSpecific<LiquibaseInstallation>, EnvironmentSpecific<LiquibaseInstallation>, Serializable {

public static final String UNIX_EXEC_NAME = "liquibase";
public static final String WINDOWS_EXEC_NAME = "liquibase.bat";

@DataBoundConstructor
public LiquibaseInstallation(String name, String home, List<? extends ToolProperty<?>> properties) {
@@ -2,7 +2,7 @@
xmlns:f="/lib/form">


<f:radioBlock inline="true" name="invokeExternal" checked="${instance.invokeExternal}" value="false"
<f:radioBlock inline="true" name="invokeExternal" checked="${instance.invokeExternal}" value="true"
title="${%Use Existing Liquibase Installation}">
<f:entry title="${%Liquibase Version}" field="installationName">
<select class="setting-input" name="installationName">
@@ -13,7 +13,7 @@
</select>
</f:entry>
</f:radioBlock>
<f:radioBlock inline="true" name="invokeExternal" checked="${!instance.invokeExternal}" value="true"
<f:radioBlock inline="true" name="invokeExternal" checked="${!instance.invokeExternal}" value="false"
title="${%Use Embedded Liquibase}">
</f:radioBlock>

0 comments on commit ceb9be7

Please sign in to comment.
You can’t perform that action at this time.