diff --git a/.travis.yml b/.travis.yml index 61b8ad299..12da4b221 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: java jdk: - - openjdk6 - openjdk7 - oraclejdk7 diff --git a/pom.xml b/pom.xml index 8fa86eece..c95660d4a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,313 +1,320 @@ - - 4.0.0 + + 4.0.0 - - org.sonatype.oss - oss-parent - 7 - + + org.sonatype.oss + oss-parent + 7 + - org.jbake - jbake-core - 2.3.0-SNAPSHOT - jar + org.jbake + jbake-core + 2.3.0-SNAPSHOT + jar - jbake - JBake is a Java based open source static site/blog generator for developers. - http://jbake.org - - - jonbullock - Jonathan Bullock - jonbullock@gmail.com - http://jonathanbullock.com - 0 - - + jbake + JBake is a Java based open source static site/blog generator for developers. + http://jbake.org + + + jonbullock + Jonathan Bullock + jonbullock@gmail.com + http://jonathanbullock.com + 0 + + - - https://github.com/jbake-org/jbake/ - scm:git:git@github.com:jbake-org/jbake.git - scm:git:https://github.com/jbake-org/jbake.git - - - - GitHub Issues - https://github.com/jbake-org/jbake/issues - + + https://github.com/jbake-org/jbake/ + scm:git:git@github.com:jbake-org/jbake.git + scm:git:https://github.com/jbake-org/jbake.git + - - - jbake-dev - jbake-dev@googlegroups.com - jbake-dev+unsubscribe@googlegroups.com - http://groups.google.com/group/jbake-dev - - - jbake-user - jbake-user@googlegroups.com - jbake-user+unsubscribe@googlegroups.com - http://groups.google.com/group/jbake-user - - + + GitHub Issues + https://github.com/jbake-org/jbake/issues + - - - The MIT License (MIT) - http://opensource.org/licenses/MIT - - + + + jbake-dev + jbake-dev@googlegroups.com + jbake-dev+unsubscribe@googlegroups.com + http://groups.google.com/group/jbake-dev + + + jbake-user + jbake-user@googlegroups.com + jbake-user+unsubscribe@googlegroups.com + http://groups.google.com/group/jbake-user + + - - UTF-8 - ${maven.build.timestamp} - yyyy-MM-dd HH:mm:ssa - - 0.1.4 - 2.4 - 1.9 - 2.0.23 - 2.3.19 - 4.10 - 1.4.2 - 8.1.12.v20130726 + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + + + + + UTF-8 + ${maven.build.timestamp} + yyyy-MM-dd HH:mm:ssa + + 0.1.4 + 2.4 + 1.9 + 2.0.23 + 2.3.19 + 4.10 + 1.4.2 + 8.1.12.v20130726 1.6.2 2.3.0 1.7.5 1.0.9 1.6.0 2.1.2.RELEASE + 3.3.2.201404171909-r - - ${project.artifactId} - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.6 - 1.6 - - - - org.apache.maven.plugins - maven-eclipse-plugin - 2.9 - - true - - - - org.apache.maven.plugins - maven-scm-plugin - 1.1 - - - checkout-example-project-freemarker - prepare-package - - checkout - - - ${project.build.directory}/example-project-freemarker - scm:git:git://github.com/jbake-org/jbake-example-project-freemarker.git - - - - checkout-example-project-groovy - prepare-package - - checkout - - - ${project.build.directory}/example-project-groovy - scm:git:git://github.com/jbake-org/jbake-example-project-groovy.git - - - - checkout-example-project-thymeleaf - prepare-package - - checkout - - - ${project.build.directory}/example-project-thymeleaf - scm:git:git://github.com/jbake-org/jbake-example-project-thymeleaf.git - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - lib/ - org.jbake.launcher.Main - org.jbake.launcher - - - lib/ - - - - - - org.apache.maven.plugins - maven-clean-plugin - 2.4.1 - - - - dist - - - - - - org.apache.maven.plugins - maven-dependency-plugin - 2.4 - - - copy-dependencies - package - - copy-dependencies - - - ${project.build.directory}/lib - test - compile - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 2.4 - - - zip-example-project-freemarker - package - - single - - - example_project_freemarker - false - - src/main/assembly/assembly-example-project-freemarker.xml - - false - - - - zip-example-project-groovy - package - - single - - - example_project_groovy - false - - src/main/assembly/assembly-example-project-groovy.xml - - false - - - - zip-example-project-thymeleaf - package - - single - - - example_project_thymeleaf - false - - src/main/assembly/assembly-example-project-thymeleaf.xml - - false - - - - make-assembly - package - - single - - - dist - jbake-${project.version} - - src/main/assembly/assembly.xml - - false - - - - - - org.jacoco - jacoco-maven-plugin - 0.6.3.201306030806 - - - prepare-agent - - prepare-agent - - - - - - org.eluder.coveralls - coveralls-maven-plugin - 2.0.1 - - - - - - - - - src/main/resources - true - - - - - - commons-io - commons-io - ${commons.io.version} - - - commons-configuration - commons-configuration - ${commons.configuration.version} - - - args4j - args4j - ${args4j.version} - - - org.freemarker - freemarker - ${freemarker.version} + + ${project.artifactId} + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.9 + + true + + + + org.apache.maven.plugins + maven-scm-plugin + 1.1 + + + checkout-example-project-freemarker + prepare-package + + checkout + + + ${project.build.directory}/example-project-freemarker + scm:git:git://github.com/jbake-org/jbake-example-project-freemarker.git + + + + checkout-example-project-groovy + prepare-package + + checkout + + + ${project.build.directory}/example-project-groovy + scm:git:git://github.com/jbake-org/jbake-example-project-groovy.git + + + + checkout-example-project-thymeleaf + prepare-package + + checkout + + + ${project.build.directory}/example-project-thymeleaf + scm:git:git://github.com/jbake-org/jbake-example-project-thymeleaf.git + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + lib/ + org.jbake.launcher.Main + org.jbake.launcher + + + lib/ + + + + + + org.apache.maven.plugins + maven-clean-plugin + 2.4.1 + + + + dist + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.4 + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/lib + test + compile + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4 + + + zip-example-project-freemarker + package + + single + + + example_project_freemarker + false + + src/main/assembly/assembly-example-project-freemarker.xml + + false + + + + zip-example-project-groovy + package + + single + + + example_project_groovy + false + + src/main/assembly/assembly-example-project-groovy.xml + + false + + + + zip-example-project-thymeleaf + package + + single + + + example_project_thymeleaf + false + + src/main/assembly/assembly-example-project-thymeleaf.xml + + false + + + + make-assembly + package + + single + + + dist + jbake-${project.version} + + src/main/assembly/assembly.xml + + false + + + + + + org.jacoco + jacoco-maven-plugin + 0.6.3.201306030806 + + + prepare-agent + + prepare-agent + + + + + + org.eluder.coveralls + coveralls-maven-plugin + 2.0.1 + + + + + + + + + src/main/resources + true + + + + + + org.eclipse.jgit + org.eclipse.jgit + ${jgit.version} + + + commons-io + commons-io + ${commons.io.version} + + + commons-configuration + commons-configuration + ${commons.configuration.version} + + + args4j + args4j + ${args4j.version} + + + org.freemarker + freemarker + ${freemarker.version} true - + com.orientechnologies orient-commons @@ -319,41 +326,38 @@ ${orientdb.version} - - junit - junit - ${junit.version} - test - - - org.assertj - assertj-core - ${assertj.version} - test - - - - org.pegdown - pegdown - ${pegdown.version} + + junit + junit + ${junit.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + + org.pegdown + pegdown + ${pegdown.version} true - - - org.asciidoctor - asciidoctor-java-integration - ${asciidoctor.java.version} + + + org.asciidoctor + asciidoctor-java-integration + ${asciidoctor.java.version} true - - - org.eclipse.jetty - jetty-server - ${jetty.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} true - + org.codehaus.groovy groovy-all @@ -366,12 +370,12 @@ ${thymeleaf.version} true - - - org.slf4j - slf4j-api - ${slf4j.version} - + + + org.slf4j + slf4j-api + ${slf4j.version} + ch.qos.logback @@ -386,5 +390,5 @@ ${logback.version} true - + diff --git a/src/main/java/org/jbake/app/ConfigUtil.java b/src/main/java/org/jbake/app/ConfigUtil.java index 0dbec8a00..581ae6670 100644 --- a/src/main/java/org/jbake/app/ConfigUtil.java +++ b/src/main/java/org/jbake/app/ConfigUtil.java @@ -2,7 +2,9 @@ import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.EnvironmentConfiguration; import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.SystemConfiguration; import java.io.File; @@ -18,6 +20,10 @@ public class ConfigUtil { public static CompositeConfiguration load(File source) throws ConfigurationException { CompositeConfiguration config = new CompositeConfiguration(); config.setListDelimiter(','); + + config.addConfiguration(new EnvironmentConfiguration()); + config.addConfiguration(new SystemConfiguration()); + File customConfigFile = new File(source, "custom.properties"); if (customConfigFile.exists()) { config.addConfiguration(new PropertiesConfiguration(customConfigFile)); diff --git a/src/main/java/org/jbake/app/FileUtil.java b/src/main/java/org/jbake/app/FileUtil.java index 3d03aca9a..9bc4f8f17 100644 --- a/src/main/java/org/jbake/app/FileUtil.java +++ b/src/main/java/org/jbake/app/FileUtil.java @@ -1,25 +1,61 @@ package org.jbake.app; -import org.jbake.parser.Engines; - import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; +import org.jbake.parser.Engines; + /** * Provides File related functions - * + * * @author Jonathan Bullock */ public class FileUtil { + /** + * Creates a temporary directory. + * @return Temporary directory. + */ + public static File createTempDirectory() { + return new File(""); + } + + /** + * Copies recursively all files and directories from source folder to destination folder. + * @param sourceFolder where elements are got. + * @param destinationFolder where elements are copied. + * @throws IOException + */ + public static void copyRecursive(Path sourceFolder, Path destinationFolder) throws IOException { + Files.walkFileTree(sourceFolder, new CopyDirVisitor(sourceFolder, destinationFolder)); + } + + /** + * Copies recursively all files and directories from source folder to a new created temp directory. + * @param sourceFolder where elements are got. + * @return Temp directory. + * @throws IOException + */ + public static Path copyRecursiveToTempDirectory(Path sourceFolder) throws IOException { + Path toFolder = Files.createTempDirectory("jbake-"); + copyRecursive(sourceFolder, toFolder); + return toFolder; + } + /** * Filters files based on their file extension. - * + * * @return Object for filtering files */ public static FileFilter getFileFilter() { @@ -27,8 +63,7 @@ public static FileFilter getFileFilter() { @Override public boolean accept(File pathname) { - return !pathname.isFile() - || Engines.getRecognizedExtensions().contains(fileExt(pathname)); + return !pathname.isFile() || Engines.getRecognizedExtensions().contains(fileExt(pathname)); } }; } @@ -39,7 +74,7 @@ public static boolean isExistingFolder(File f) { /** * Works out the folder where JBake is running from. - * + * * @return File referencing folder JBake is running from * @throws Exception */ @@ -75,8 +110,9 @@ public static String fileExt(String name) { /** * Computes the hash of a file or directory. - * - * @param sourceFile the original file or directory + * + * @param sourceFile + * the original file or directory * @return an hex string representing the SHA1 hash of the file or directory. * @throws Exception */ @@ -92,7 +128,8 @@ public static String sha1(File sourceFile) throws Exception { return sb.toString(); } - private static void updateDigest(final MessageDigest digest, final File sourceFile, final byte[] buffer) throws IOException { + private static void updateDigest(final MessageDigest digest, final File sourceFile, final byte[] buffer) + throws IOException { if (sourceFile.isFile()) { InputStream fis = new FileInputStream(sourceFile); int numRead; @@ -105,7 +142,7 @@ private static void updateDigest(final MessageDigest digest, final File sourceFi fis.close(); } else if (sourceFile.isDirectory()) { File[] files = sourceFile.listFiles(); - if (files!=null) { + if (files != null) { for (File file : files) { updateDigest(digest, file, buffer); } @@ -113,30 +150,60 @@ private static void updateDigest(final MessageDigest digest, final File sourceFi } } - /** - * platform independent file.getPath() - * - * @param file the file to transform, or {@code null} - * @return The result of file.getPath() with all path Separators beeing a "/", or {@code null} - * Needed to transform Windows path separators into slashes. - */ - public static String asPath(File file) { - if(file == null) { - return null; - } - return asPath(file.getPath()); - } - - /** - * platform independent file.getPath() - * - * @param path the path to transform, or {@code null} - * @return The result will have alle platform path separators replaced by "/". - */ - public static String asPath(String path) { - if(path == null) { - return null; - } - return path.replace(File.separator, "/"); - } + /** + * platform independent file.getPath() + * + * @param file + * the file to transform, or {@code null} + * @return The result of file.getPath() with all path Separators beeing a "/", or {@code null} Needed to transform + * Windows path separators into slashes. + */ + public static String asPath(File file) { + if (file == null) { + return null; + } + return asPath(file.getPath()); + } + + /** + * platform independent file.getPath() + * + * @param path + * the path to transform, or {@code null} + * @return The result will have alle platform path separators replaced by "/". + */ + public static String asPath(String path) { + if (path == null) { + return null; + } + return path.replace(File.separator, "/"); + } + + private static class CopyDirVisitor extends SimpleFileVisitor { + + private Path fromPath; + private Path toPath; + + public CopyDirVisitor(Path fromPath, Path toPath) { + this.fromPath = fromPath; + this.toPath = toPath; + } + + private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING; + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + Path targetPath = toPath.resolve(fromPath.relativize(dir)); + if (!Files.exists(targetPath)) { + Files.createDirectory(targetPath); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.copy(file, toPath.resolve(fromPath.relativize(file)), copyOption); + return FileVisitResult.CONTINUE; + } + } } diff --git a/src/main/java/org/jbake/app/GitUtil.java b/src/main/java/org/jbake/app/GitUtil.java new file mode 100644 index 000000000..6e9d6ee70 --- /dev/null +++ b/src/main/java/org/jbake/app/GitUtil.java @@ -0,0 +1,272 @@ +package org.jbake.app; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryBuilder; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.lib.TreeFormatter; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.CredentialsProvider; + +/** + * Util class for executing git operations. + * + * @author Alex Soto + * + */ +public class GitUtil { + + /** + * Inits a folder as git directory. + * + * @param folder which is initialized as git repository. + * @return Git instance. + * @throws GitAPIException + */ + public static Git initGit(File folder) throws GitAPIException { + return Git.init().setDirectory(folder).call(); + } + + /** + * Opens a git repo. + * + * @param folder git repository. + * @return Git instance. + * @throws IOException + */ + public static Git openGitRepository(File folder) throws IOException { + RepositoryBuilder repositoryBuilder = new RepositoryBuilder().readEnvironment().findGitDir(folder); + File gitDir = repositoryBuilder.getGitDir(); + return Git.open(gitDir); + } + + /** + * Adds remote configuration to git configuration file if it is not already set. + * + * @param git instance. + * @param remote name of remote upstream (origin is the most used). + * @param remoteUrl of remote repo. + */ + public static void addRemoteConfig(Git git, String remote, String remoteUrl) { + StoredConfig storedConfig = git.getRepository().getConfig(); + + if(storedConfig.getString("remote", remote, "url") == null) { + storedConfig.setString("remote", remote, "url", + remoteUrl); + } + } + + /** + * Checks if given directory is a git repo. + * + * @param folder to check. + * @return True if it is a git repo, false otherwise. + * @throws IOException + */ + public static boolean isGitDirectory(File folder) throws IOException { + RepositoryBuilder repositoryBuilder = new RepositoryBuilder().readEnvironment().findGitDir(folder); + return repositoryBuilder.getGitDir() != null; + } + + /** + * Adds element to stage area. + * + * @param git instance. + * @param pattern of elements to be added. + * @throws GitAPIException + */ + public static void add(Git git, String pattern) throws GitAPIException { + git.add().addFilepattern(pattern).call(); + } + + /** + * Commits elements previously added. + * + * @param git instance. + * @param message to be used as commit message. + * @throws GitAPIException + */ + public static void commit(Git git, String message) throws GitAPIException { + git.commit().setMessage(message).call(); + } + + /** + * Remove element from stage area. + * + * @param git instance. + * @param pattern of files to be removed. + * @throws GitAPIException + */ + public static void rm(Git git, String pattern) throws GitAPIException { + git.rm().addFilepattern(pattern).call(); + } + + public static void addAndCommit(Git git, String pattern, String message) throws GitAPIException { + add(git, pattern); + commit(git, message); + } + + public static void addAndRemove(Git git, String pattern, String message) throws GitAPIException { + add(git, pattern); + rm(git, message); + } + + /** + * Creates an orphan branch. + * + * @param git instance. + * @param branchName to be created. + * @param personIdent information. + * @return Ref created. + * @throws IOException + * @throws GitAPIException + */ + public static Ref createOrphanBranch(Git git, String branchName, PersonIdent personIdent) throws IOException, GitAPIException { + + Repository repository = git.getRepository(); + boolean success = false; + + String message = "Created branch " + branchName; + ObjectInserter odi = repository.newObjectInserter(); + try { + // Create a blob object to insert into a tree + ObjectId blobId = odi.insert(Constants.OBJ_BLOB, message.getBytes(Constants.CHARACTER_ENCODING)); + + // Create a tree object to reference from a commit + TreeFormatter tree = new TreeFormatter(); + tree.append(".branch", FileMode.REGULAR_FILE, blobId); + ObjectId treeId = odi.insert(tree); + + // Create a commit object + CommitBuilder commit = new CommitBuilder(); + commit.setAuthor(personIdent); + commit.setCommitter(personIdent); + commit.setEncoding(Constants.CHARACTER_ENCODING); + commit.setMessage(message); + commit.setTreeId(treeId); + + // Insert the commit into the repository + ObjectId commitId = odi.insert(commit); + odi.flush(); + + RevWalk revWalk = new RevWalk(repository); + try { + RevCommit revCommit = revWalk.parseCommit(commitId); + if (!branchName.startsWith("refs/")) { + branchName = "refs/heads/" + branchName; + } + RefUpdate ru = repository.updateRef(branchName); + ru.setNewObjectId(commitId); + ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result rc = ru.forceUpdate(); + switch (rc) { + case NEW: + case FORCED: + case FAST_FORWARD: + success = true; + break; + default: + success = false; + } + + if(success) { + return ru.getRef(); + } + + } finally { + revWalk.release(); + } + } finally { + odi.release(); + } + + return null; + } + + /** + * Checks if branch is created. + * + * @param git instance. + * @param branchName + * @return True if branch is created, faƱse otherwise. + * @throws GitAPIException + */ + public static boolean isBranchCreated(Git git, String branchName) throws GitAPIException { + List refList = git.branchList().call(); + + for (Ref ref : refList) { + if(ref.getName().equals(branchName)) { + return true; + } + } + + return false; + + } + + /** + * Checkouts branch. + * + * @param git instance. + * @param branchName to checkout. + * @throws GitAPIException + */ + public static void checkoutBranch(Git git, String branchName) throws GitAPIException { + git.checkout().setName(branchName).call(); + } + + /** + * Forces a remove of given branch. + * + * @param git instance. + * @param branchName to be removed. + * @throws GitAPIException + */ + public static void forceRemoveBranch(Git git, String branchName) throws GitAPIException { + git.branchDelete().setForce(true).call(); + } + + public static void checkoutAndRemove(Git git, String branchName) throws GitAPIException { + checkoutBranch(git, branchName); + forceRemoveBranch(git, branchName); + } + + /** + * Forces a push to given ref. + * @param git instance. + * @param credentialsProvider to authenticate against remote server. + * @param ref to push. + * @param remote name of remote upstream (origin is the most used). + * @throws GitAPIException + */ + public static void forcePush(Git git, CredentialsProvider credentialsProvider, Ref ref, String remote) + throws GitAPIException { + git.push().setCredentialsProvider(credentialsProvider).add(ref).setRemote(remote).setForce(true).call(); + } + + /** + * Closes git repo. + * @param git instance. + */ + public static void closeRepo(Git git) { + git.close(); + } + +} diff --git a/src/main/java/org/jbake/launcher/LaunchOptions.java b/src/main/java/org/jbake/launcher/LaunchOptions.java index 40f79b4a6..3fd20d11c 100644 --- a/src/main/java/org/jbake/launcher/LaunchOptions.java +++ b/src/main/java/org/jbake/launcher/LaunchOptions.java @@ -1,11 +1,12 @@ package org.jbake.launcher; import java.io.File; -import java.util.ArrayList; -import java.util.List; +import java.util.Map; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.MapOptionHandler; +import org.kohsuke.args4j.spi.StringArrayOptionHandler; public class LaunchOptions { @Argument(index = 0, usage = "source folder of site content (with templates and assets), if not supplied will default to current directory", metaVar = "") @@ -20,6 +21,9 @@ public class LaunchOptions { @Option(name = "-i", aliases = {"--init"}, usage="initialises required folder structure with default templates") private boolean init; + @Option(name = "-g", aliases = {"--git"}, usage="initialises the folder as a git repository, it must be used alongside -i (--init) option") + private boolean git; + @Option(name = "-s", aliases = {"--server"}, usage="runs HTTP server to serve out baked site, if no is supplied will default to a folder called \"output\" in the current directory") private boolean runServer; @@ -29,6 +33,12 @@ public class LaunchOptions { @Option(name = "--reset", usage="clears the local cache, enforcing rendering from scratch") private boolean clearCache; + @Option(name = "--publisher-params", usage="creates a map of parameters that can be used inside publisher module. For example --publisher-params password=mysecretpassword. See publishers documentation for valid options", handler=MapOptionHandler.class) + private Map publisherParams; + + @Option(name = "--publishers", usage="publishes baked content to specified publishers. Currently jbake provides out-of-the-box github publisher") + private String[] publishers; + public File getSource() { if (source != null) { return new File(source); @@ -54,6 +64,22 @@ public String getDestinationValue() { return destination; } + public Map getPublisherParams() { + return publisherParams; + } + + public String[] getPublishers() { + return publishers; + } + + public boolean isPublisher() { + return publishers != null && publishers.length > 0; + } + + public boolean isGit() { + return git; + } + public boolean isHelpNeeded() { return helpNeeded; } @@ -70,7 +96,11 @@ public boolean isClearCache() { return clearCache; } + public boolean isPublisherParameters() { + return this.publisherParams != null && this.publisherParams.size() > 0; + } + public boolean isBake() { - return bake || !(isHelpNeeded() || isRunServer() || isInit()); + return bake || !(isHelpNeeded() || isRunServer() || isInit() || isPublisher() || isGit()); } } diff --git a/src/main/java/org/jbake/launcher/Main.java b/src/main/java/org/jbake/launcher/Main.java index e57ad4f61..ae86581eb 100644 --- a/src/main/java/org/jbake/launcher/Main.java +++ b/src/main/java/org/jbake/launcher/Main.java @@ -4,12 +4,18 @@ import java.io.StringWriter; import java.text.MessageFormat; import java.util.List; +import java.util.ServiceLoader; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.ConfigurationException; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; import org.jbake.app.ConfigUtil; import org.jbake.app.FileUtil; +import org.jbake.app.GitUtil; import org.jbake.app.Oven; +import org.jbake.publisher.GithubPublisher; +import org.jbake.spi.Publisher; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; @@ -24,6 +30,8 @@ public class Main { private final String USAGE_PREFIX = "Usage: jbake"; private final String ALT_USAGE_PREFIX = " or jbake"; + private static ServiceLoader publisherSetLoader = ServiceLoader.load(Publisher.class); + /** * Runs the app with the given arguments. * @@ -54,7 +62,7 @@ private void bake(LaunchOptions options) { System.exit(1); } } - + private void run(String[] args) { LaunchOptions res = parseArguments(args); @@ -77,6 +85,10 @@ private void run(String[] args) { bake(res); } + if(res.isPublisher()) { + resolvePublishers(config, res); + } + if (res.isInit()) { if (res.getSourceValue() != null) { // if type has been supplied then use it @@ -85,6 +97,20 @@ private void run(String[] args) { // default to freemarker if no value has been supplied initStructure(config, "freemarker"); } + + if(res.isGit()) { + try { + Git git = GitUtil.initGit(new File(".")); + GitUtil.closeRepo(git); + System.out.println("Git repository initialized."); + } catch (GitAPIException e) { + e.printStackTrace(); + System.exit(1); + } + } + + System.exit(0); + } if (res.isRunServer()) { @@ -97,7 +123,26 @@ private void run(String[] args) { } } - private LaunchOptions parseArguments(String[] args) { + + private void resolvePublishers(CompositeConfiguration config, LaunchOptions res) { + + String[] publishers = res.getPublishers(); + + for (String publisherName : publishers) { + + for (Publisher publisher : publisherSetLoader) { + + if(publisherName.equals(publisher.publisherName())) { + publisher.publish(config, res); + } + } + } + + System.exit(0); + + } + + private LaunchOptions parseArguments(String[] args) { LaunchOptions res = new LaunchOptions(); CmdLineParser parser = new CmdLineParser(res); @@ -134,7 +179,6 @@ private void initStructure(CompositeConfiguration config, String type) { File codeFolder = FileUtil.getRunningLocation(); init.run(new File("."), codeFolder, type); System.out.println("Base folder structure successfully created."); - System.exit(0); } catch (Exception e) { System.err.println("Failed to initalise structure!"); e.printStackTrace(); diff --git a/src/main/java/org/jbake/publisher/GithubPublisher.java b/src/main/java/org/jbake/publisher/GithubPublisher.java new file mode 100644 index 000000000..b1d79dadd --- /dev/null +++ b/src/main/java/org/jbake/publisher/GithubPublisher.java @@ -0,0 +1,134 @@ +package org.jbake.publisher; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.text.MessageFormat; + +import org.apache.commons.configuration.Configuration; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.jbake.app.FileUtil; +import org.jbake.app.GitUtil; +import org.jbake.launcher.LaunchOptions; +import org.jbake.spi.Publisher; + +public class GithubPublisher implements Publisher { + + private static final String GH_PAGES = "gh-pages"; + private static final String GIT_MASTER = "git.master"; + private static final String GIT_USER = "git.user"; + private static final String GIT_EMAIL = "git.email"; + private static final String GIT_PASSWORD = "git.password"; + private static final String GITHUB_URL = "github.url"; + + private static final String PUBLISHER_NAME = "github"; + + private Configuration configuration; + private File sourceDirectory; + private File outputDirectory; + private LaunchOptions launchOptions; + + @Override + public String publisherName() { + return PUBLISHER_NAME; + } + + @Override + public void publish(Configuration configuration, LaunchOptions options) { + + initializeAttributes(configuration, options); + + try { + ensureDestination(); + publishToGhPagesBranch(); + } catch (IOException e) { + throw new PublisherException(e); + } + + } + + private void initializeAttributes(Configuration configuration, LaunchOptions options) { + this.configuration = configuration; + this.launchOptions = options; + this.sourceDirectory = options.getSource(); + this.outputDirectory = options.getDestination(); + } + + private void ensureDestination() { + if(this.outputDirectory == null) { + outputDirectory = new File(configuration.getString("destination.folder")); + } + } + + private void publishToGhPagesBranch() throws IOException { + + if(GitUtil.isGitDirectory(sourceDirectory)) { + Git git = GitUtil.openGitRepository(sourceDirectory); + + try { + + String username = this.configuration.getString(GIT_USER); + String email = this.configuration.getString(GIT_EMAIL); + + if(GitUtil.isBranchCreated(git, GH_PAGES)) { + GitUtil.forceRemoveBranch(git, "refs/heads/"+GH_PAGES); + } + + Ref ref = GitUtil.createOrphanBranch(git, GH_PAGES, new PersonIdent(username, email)); + + String workingBranch = this.configuration.getString(GIT_MASTER, Constants.MASTER); + GitUtil.checkoutBranch(git, workingBranch); + + Path tempDirectory = FileUtil.copyRecursiveToTempDirectory(this.outputDirectory.toPath()); + + GitUtil.checkoutBranch(git, GH_PAGES); + FileUtil.copyRecursive(tempDirectory, git.getRepository().getDirectory().getParentFile().toPath()); + + GitUtil.addAndCommit(git, ".", "JBake " + this.configuration.getString("version") + " (" + this.configuration.getString("build.timestamp") + ") [http://jbake.org]"); + + String githubUrl = this.configuration.getString(GITHUB_URL, ""); + + if(!"".equals(githubUrl)) { + sendToRemote(git, ref, githubUrl); + } + + GitUtil.checkoutBranch(git, workingBranch); + + } catch (GitAPIException e) { + throw new PublisherException(e); + } finally { + git.close(); + } + + } else { + throw new PublisherException(MessageFormat.format("Source directory {0} must be a git repository in order to publish to github.", sourceDirectory.getAbsolutePath())); + } + } + + private void sendToRemote(Git git, Ref ref, String remoteUrl) throws GitAPIException { + GitUtil.addRemoteConfig(git, Constants.DEFAULT_REMOTE_NAME, remoteUrl); + GitUtil.forcePush(git, getCredentialsProvider(), ref, Constants.DEFAULT_REMOTE_NAME); + } + + private CredentialsProvider getCredentialsProvider() { + + String username = this.configuration.getString(GIT_USER, ""); + + String password = ""; + if(this.launchOptions.isPublisherParameters() && this.launchOptions.getPublisherParams().containsKey(GIT_PASSWORD)) { + password = this.launchOptions.getPublisherParams().get(GIT_PASSWORD); + } else { + password = this.configuration.getString(GIT_PASSWORD, ""); + } + + return new UsernamePasswordCredentialsProvider(username, password); + + } + +} diff --git a/src/main/java/org/jbake/publisher/PublisherException.java b/src/main/java/org/jbake/publisher/PublisherException.java new file mode 100644 index 000000000..510b49835 --- /dev/null +++ b/src/main/java/org/jbake/publisher/PublisherException.java @@ -0,0 +1,22 @@ +package org.jbake.publisher; + +public class PublisherException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public PublisherException(String message) { + super(message); + } + + public PublisherException(String message, Throwable e) { + super(message, e); + } + + public PublisherException(Throwable e) { + super(e); + } + +} diff --git a/src/main/java/org/jbake/spi/Publisher.java b/src/main/java/org/jbake/spi/Publisher.java new file mode 100644 index 000000000..b4248247b --- /dev/null +++ b/src/main/java/org/jbake/spi/Publisher.java @@ -0,0 +1,11 @@ +package org.jbake.spi; + +import org.apache.commons.configuration.Configuration; +import org.jbake.launcher.LaunchOptions; + +public interface Publisher { + + String publisherName(); + void publish(Configuration configuration, LaunchOptions options); + +} diff --git a/src/main/resources/META-INF/services/org.jbake.spi.Publisher b/src/main/resources/META-INF/services/org.jbake.spi.Publisher new file mode 100644 index 000000000..f2ed48d7c --- /dev/null +++ b/src/main/resources/META-INF/services/org.jbake.spi.Publisher @@ -0,0 +1 @@ +org.jbake.publisher.GithubPublisher \ No newline at end of file diff --git a/src/main/resources/org/eclipse/jgit/internal/JGitText_en_US.properties b/src/main/resources/org/eclipse/jgit/internal/JGitText_en_US.properties new file mode 100644 index 000000000..42874ab87 --- /dev/null +++ b/src/main/resources/org/eclipse/jgit/internal/JGitText_en_US.properties @@ -0,0 +1,573 @@ +abbreviationLengthMustBeNonNegative=Abbreviation length must not be negative. +abortingRebase=Aborting rebase: resetting to {0} +abortingRebaseFailed=Could not abort rebase +abortingRebaseFailedNoOrigHead=Could not abort rebase since ORIG_HEAD is null +advertisementCameBefore=advertisement of {0}^{} came before {1} +advertisementOfCameBefore=advertisement of {0}^{} came before {1} +amazonS3ActionFailed={0} of ''{1}'' failed: {2} {3} +amazonS3ActionFailedGivingUp={0} of ''{1}'' failed: Giving up after {2} attempts. +ambiguousObjectAbbreviation=Object abbreviation {0} is ambiguous +aNewObjectIdIsRequired=A NewObjectId is required. +anExceptionOccurredWhileTryingToAddTheIdOfHEAD=An exception occurred while trying to add the Id of HEAD +anSSHSessionHasBeenAlreadyCreated=An SSH session has been already created +applyingCommit=Applying {0} +archiveFormatAlreadyAbsent=Archive format already absent: {0} +archiveFormatAlreadyRegistered=Archive format already registered: {0} +argumentIsNotAValidCommentString=Invalid comment: {0} +atLeastOnePathIsRequired=At least one path is required. +atLeastOnePatternIsRequired=At least one pattern is required. +atLeastTwoFiltersNeeded=At least two filters needed. +authenticationNotSupported=authentication not supported +badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal) +badEntryDelimiter=Bad entry delimiter +badEntryName=Bad entry name: {0} +badEscape=Bad escape: {0} +badGroupHeader=Bad group header +badObjectType=Bad object type: {0} +badSectionEntry=Bad section entry: {0} +bareRepositoryNoWorkdirAndIndex=Bare Repository has neither a working tree, nor an index +base64InputNotProperlyPadded=Base64 input not properly padded. +baseLengthIncorrect=base length incorrect +bitmapMissingObject=Bitmap at {0} is missing {1}. +bitmapsMustBePrepared=Bitmaps must be prepared before they may be written. +blameNotCommittedYet=Not Committed Yet +blobNotFound=Blob not found: {0} +blobNotFoundForPath=Blob not found: {0} for path: {1} +branchNameInvalid=Branch name {0} is not allowed +buildingBitmaps=Building bitmaps +cachedPacksPreventsIndexCreation=Using cached packs prevents index creation +cachedPacksPreventsListingObjects=Using cached packs prevents listing objects +cannotBeCombined=Cannot be combined. +cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included. +cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}. +cannotChangeToComment=Cannot change a non-comment line to a comment line. +cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff. +cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}. +cannotCommitOnARepoWithState=Cannot commit on a repo with state: {0} +cannotCommitWriteTo=Cannot commit write to {0} +cannotConnectPipes=cannot connect pipes +cannotConvertScriptToText=Cannot convert script to text +cannotCreateConfig=cannot create config +cannotCreateDirectory=Cannot create directory {0} +cannotCreateHEAD=cannot create HEAD +cannotCreateIndexfile=Cannot create an index file with name {0} +cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted +cannotDeleteFile=Cannot delete file: {0} +cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0} +cannotDeleteStaleTrackingRef2=Cannot delete stale tracking ref {0}: {1} +cannotDetermineProxyFor=Cannot determine proxy for {0} +cannotDownload=Cannot download {0} +cannotExecute=cannot execute: {0} +cannotGet=Cannot get {0} +cannotListRefs=cannot list refs +cannotLock=Cannot lock {0} +cannotLockPackIn=Cannot lock pack in {0} +cannotMatchOnEmptyString=Cannot match on empty string. +cannotMoveIndexTo=Cannot move index to {0} +cannotMovePackTo=Cannot move pack to {0} +cannotOpenService=cannot open {0} +cannotParseDate=The date specification "{0}" could not be parsed with the following formats: {1} +cannotParseGitURIish=Cannot parse Git URI-ish +cannotPullOnARepoWithState=Cannot pull into a repository with state: {0} +cannotRead=Cannot read {0} +cannotReadBlob=Cannot read blob {0} +cannotReadCommit=Cannot read commit {0} +cannotReadFile=Cannot read file {0} +cannotReadHEAD=cannot read HEAD: {0} {1} +cannotReadObject=Cannot read object +cannotReadTree=Cannot read tree {0} +cannotRebaseWithoutCurrentHead=Can not rebase without a current HEAD +cannotResolveLocalTrackingRefForUpdating=Cannot resolve local tracking ref {0} for updating. +cannotSquashFixupWithoutPreviousCommit=Cannot {0} without previous commit. +cannotStoreObjects=cannot store objects +cannotUnloadAModifiedTree=Cannot unload a modified tree. +cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index. +canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported. +canOnlyRevertCommitsWithOneParent=Cannot revert commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported +cantFindObjectInReversePackIndexForTheSpecifiedOffset=Can't find object in (reverse) pack index for the specified offset {0} +cantPassMeATree=Can't pass me a tree! +channelMustBeInRange0_255=channel {0} must be in range [0, 255] +characterClassIsNotSupported=The character class {0} is not supported. +checkoutConflictWithFile=Checkout conflict with file: {0} +checkoutConflictWithFiles=Checkout conflict with files: {0} +checkoutUnexpectedResult=Checkout returned unexpected result {0} +classCastNotA=Not a {0} +cloneNonEmptyDirectory=Destination path "{0}" already exists and is not an empty directory +collisionOn=Collision on {0} +commandWasCalledInTheWrongState=Command {0} was called in the wrong state +commitAlreadyExists=exists {0} +commitMessageNotSpecified=commit message not specified +commitOnRepoWithoutHEADCurrentlyNotSupported=Commit on repo without HEAD currently not supported +commitAmendOnInitialNotPossible=Amending is not possible on initial commit. +compressingObjects=Compressing objects +connectionFailed=connection failed +connectionTimeOut=Connection time out: {0} +contextMustBeNonNegative=context must be >= 0 +corruptionDetectedReReadingAt=Corruption detected re-reading at {0} +corruptObjectBadStream=bad stream +corruptObjectBadStreamCorruptHeader=bad stream, corrupt header +corruptObjectGarbageAfterSize=garbage after size +corruptObjectIncorrectLength=incorrect length +corruptObjectInvalidEntryMode=invalid entry mode +corruptObjectInvalidMode=invalid mode +corruptObjectInvalidMode2=invalid mode {0} +corruptObjectInvalidMode3=invalid mode {0} for {1} ''{2}'' in {3}. +corruptObjectInvalidType=invalid type +corruptObjectInvalidType2=invalid type {0} +corruptObjectMalformedHeader=malformed header: {0} +corruptObjectNegativeSize=negative size +corruptObjectNoAuthor=no author +corruptObjectNoCommitter=no committer +corruptObjectNoHeader=no header +corruptObjectNoObject=no object +corruptObjectNoTaggerBadHeader=no tagger/bad header +corruptObjectNoTaggerHeader=no tagger header +corruptObjectNoTagName=no tag name +corruptObjectNotree=no tree +corruptObjectNoType=no type +corruptObjectPackfileChecksumIncorrect=Packfile checksum incorrect. +couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts +couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen +couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen +couldNotGetAdvertisedRef=Could not get advertised Ref for branch {0} +couldNotGetRepoStatistics=Could not get repository statistics +couldNotLockHEAD=Could not lock HEAD +couldNotReadIndexInOneGo=Could not read index in one go, only {0} out of {1} read +couldNotReadObjectWhileParsingCommit=Could not read an object while parsing commit {0} +couldNotRenameDeleteOldIndex=Could not rename delete old index +couldNotRenameTemporaryFile=Could not rename temporary file {0} to new location {1} +couldNotRenameTemporaryIndexFileToIndex=Could not rename temporary index file to index +couldNotURLEncodeToUTF8=Could not URL encode to UTF-8 +couldNotWriteFile=Could not write file {0} +countingObjects=Counting objects +createBranchFailedUnknownReason=Create branch failed for unknown reason +createBranchUnexpectedResult=Create branch returned unexpected result {0} +createNewFileFailed=Could not create new file {0} +credentialPassword=Password +credentialUsername=Username +daemonAlreadyRunning=Daemon already running +daysAgo={0} days ago +deleteBranchUnexpectedResult=Delete branch returned unexpected result {0} +deleteFileFailed=Could not delete file {0} +deleteTagUnexpectedResult=Delete tag returned unexpected result {0} +deletingNotSupported=Deleting {0} not supported. +destinationIsNotAWildcard=Destination is not a wildcard. +detachedHeadDetected=HEAD is detached +dirCacheDoesNotHaveABackingFile=DirCache does not have a backing file +dirCacheFileIsNotLocked=DirCache {0} not locked +dirCacheIsNotLocked=DirCache is not locked +DIRCChecksumMismatch=DIRC checksum mismatch +DIRCExtensionIsTooLargeAt=DIRC extension {0} is too large at {1} bytes. +DIRCExtensionNotSupportedByThisVersion=DIRC extension {0} not supported by this version. +DIRCHasTooManyEntries=DIRC has too many entries. +DIRCUnrecognizedExtendedFlags=Unrecognized extended flags: {0} +dirtyFilesExist=Dirty files exist. Refusing to merge +doesNotHandleMode=Does not handle mode {0} ({1}) +downloadCancelled=Download cancelled +downloadCancelledDuringIndexing=Download cancelled during indexing +duplicateAdvertisementsOf=duplicate advertisements of {0} +duplicateRef=Duplicate ref: {0} +duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0} +duplicateStagesNotAllowed=Duplicate stages not allowed +eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called. +emptyCommit=No changes +emptyPathNotPermitted=Empty path not permitted. +encryptionError=Encryption error: {0} +endOfFileInEscape=End of file in escape +entryNotFoundByPath=Entry not found by path: {0} +enumValueNotSupported2=Invalid value: {0}.{1}={2} +enumValueNotSupported3=Invalid value: {0}.{1}.{2}={3} +enumValuesNotAvailable=Enumerated values of type {0} not available +errorDecodingFromFile=Error decoding from file {0} +errorEncodingFromFile=Error encoding from file {0} +errorInBase64CodeReadingStream=Error in Base64 code reading stream. +errorInPackedRefs=error in packed-refs +errorInvalidProtocolWantedOldNewRef=error: invalid protocol: wanted 'old new ref' +errorListing=Error listing {0} +errorOccurredDuringUnpackingOnTheRemoteEnd=error occurred during unpacking on the remote end: {0} +errorReadingInfoRefs=error reading info/refs +errorSymlinksNotSupported=Symlinks are not supported with this OS/JRE +exceptionCaughtDuringExecutionOfAddCommand=Exception caught during execution of add command +exceptionCaughtDuringExecutionOfArchiveCommand=Exception caught during execution of archive command +exceptionCaughtDuringExecutionOfCherryPickCommand=Exception caught during execution of cherry-pick command. {0} +exceptionCaughtDuringExecutionOfCommitCommand=Exception caught during execution of commit command +exceptionCaughtDuringExecutionOfFetchCommand=Exception caught during execution of fetch command +exceptionCaughtDuringExecutionOfLsRemoteCommand=Exception caught during execution of ls-remote command +exceptionCaughtDuringExecutionOfMergeCommand=Exception caught during execution of merge command. {0} +exceptionCaughtDuringExecutionOfPullCommand=Exception caught during execution of pull command +exceptionCaughtDuringExecutionOfPushCommand=Exception caught during execution of push command +exceptionCaughtDuringExecutionOfResetCommand=Exception caught during execution of reset command. {0} +exceptionCaughtDuringExecutionOfRevertCommand=Exception caught during execution of revert command. {0} +exceptionCaughtDuringExecutionOfRmCommand=Exception caught during execution of rm command +exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of tag command +exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command +exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1} +expectedACKNAKFoundEOF=Expected ACK/NAK, found EOF +expectedACKNAKGot=Expected ACK/NAK, got: {0} +expectedBooleanStringValue=Expected boolean string value +expectedCharacterEncodingGuesses=Expected {0} character encoding guesses +expectedEOFReceived=expected EOF; received ''{0}'' instead +expectedGot=expected ''{0}'', got ''{1}'' +expectedLessThanGot=expected less than ''{0}'', got ''{1}'' +expectedPktLineWithService=expected pkt-line with '# service=-', got ''{0}'' +expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1} +expectedReportForRefNotReceived={0}: expected report for ref {1} not received +failedUpdatingRefs=failed updating refs +failureDueToOneOfTheFollowing=Failure due to one of the following: +failureUpdatingFETCH_HEAD=Failure updating FETCH_HEAD: {0} +failureUpdatingTrackingRef=Failure updating tracking ref {0}: {1} +fileCannotBeDeleted=File cannot be deleted: {0} +fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes). +fileIsTooLarge=File is too large: {0} +fileModeNotSetForPath=FileMode not set for path {0} +flagIsDisposed={0} is disposed. +flagNotFromThis={0} not from this. +flagsAlreadyCreated={0} flags already created. +funnyRefname=funny refname +gcFailed=Garbage collection failed. +gitmodulesNotFound=.gitmodules not found in tree. +headRequiredToStash=HEAD required to stash local changes +hoursAgo={0} hours ago +hugeIndexesAreNotSupportedByJgitYet=Huge indexes are not supported by jgit, yet +hunkBelongsToAnotherFile=Hunk belongs to another file +hunkDisconnectedFromFile=Hunk disconnected from file +hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1} +illegalArgumentNotA=Not {0} +illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed +illegalPackingPhase=Illegal packing phase {0} +illegalStateExists=exists {0} +improperlyPaddedBase64Input=Improperly padded Base64 input. +incorrectHashFor=Incorrect hash for {0}; computed {1} as a {2} from {3} bytes. +incorrectOBJECT_ID_LENGTH=Incorrect OBJECT_ID_LENGTH. +indexFileIsInUse=Index file is in use +indexFileIsTooLargeForJgit=Index file is too large for jgit +indexSignatureIsInvalid=Index signature is invalid: {0} +indexWriteException=Modified index could not be written +inMemoryBufferLimitExceeded=In-memory buffer limit exceeded +inputStreamMustSupportMark=InputStream must support mark() +integerValueOutOfRange=Integer value {0}.{1} out of range +internalRevisionError=internal revision error +internalServerError=internal server error +interruptedWriting=Interrupted writing {0} +inTheFuture=in the future +invalidAdvertisementOf=invalid advertisement of {0} +invalidAncestryLength=Invalid ancestry length +invalidBooleanValue=Invalid boolean value: {0}.{1}={2} +invalidChannel=Invalid channel {0} +invalidCharacterInBase64Data=Invalid character in Base64 data. +invalidCommitParentNumber=Invalid commit parent number +invalidEncryption=Invalid encryption +invalidGitdirRef = Invalid .git reference in file ''{0}'' +invalidGitType=invalid git type: {0} +invalidId=Invalid id {0} +invalidIdLength=Invalid id length {0}; should be {1} +invalidIntegerValue=Invalid integer value: {0}.{1}={2} +invalidKey=Invalid key: {0} +invalidLineInConfigFile=Invalid line in config file +invalidModeFor=Invalid mode {0} for {1} {2} in {3}. +invalidModeForPath=Invalid mode {0} for path {1} +invalidObject=Invalid {0} {1}:{2} +invalidOldIdSent=invalid old id sent +invalidPacketLineHeader=Invalid packet line header: {0} +invalidPath=Invalid path: {0} +invalidPathContainsSeparator=Invalid path (contains separator ''{0}''): {1} +invalidPathPeriodAtEndWindows=Invalid path (period at end is ignored by Windows): {0} +invalidPathSpaceAtEndWindows=Invalid path (space at end is ignored by Windows): {0} +invalidPathReservedOnWindows=Invalid path (''{0}'' is reserved on Windows): {1} +invalidReflogRevision=Invalid reflog revision: {0} +invalidRefName=Invalid ref name: {0} +invalidRemote=Invalid remote: {0} +invalidStageForPath=Invalid stage {0} for path {1} +invalidTagOption=Invalid tag option: {0} +invalidTimeout=Invalid timeout: {0} +invalidURL=Invalid URL {0} +invalidWildcards=Invalid wildcards {0} +invalidRefSpec=Invalid refspec {0} +invalidWindowSize=Invalid window size +isAStaticFlagAndHasNorevWalkInstance={0} is a static flag and has no RevWalk instance +JRELacksMD5Implementation=JRE lacks MD5 implementation +kNotInRange=k {0} not in {1} - {2} +largeObjectExceedsByteArray=Object {0} exceeds 2 GiB byte array limit +largeObjectExceedsLimit=Object {0} exceeds {1} limit, actual size is {2} +largeObjectException={0} exceeds size limit +largeObjectOutOfMemory=Out of memory loading {0} +lengthExceedsMaximumArraySize=Length exceeds maximum array size +listingAlternates=Listing alternates +localObjectsIncomplete=Local objects incomplete. +localRefIsMissingObjects=Local ref {0} is missing object(s). +lockCountMustBeGreaterOrEqual1=lockCount must be >= 1 +lockError=lock error: {0} +lockOnNotClosed=Lock on {0} not closed. +lockOnNotHeld=Lock on {0} not held. +malformedpersonIdentString=Malformed PersonIdent string (no < was found): {0} +maxCountMustBeNonNegative=max count must be >= 0 +mergeConflictOnNonNoteEntries=Merge conflict on non-note entries: base = {0}, ours = {1}, theirs = {2} +mergeConflictOnNotes=Merge conflict on note {0}. base = {1}, ours = {2}, theirs = {2} +mergeStrategyAlreadyExistsAsDefault=Merge strategy "{0}" already exists as a default strategy +mergeStrategyDoesNotSupportHeads=merge strategy {0} does not support {1} heads to be merged into HEAD +mergeUsingStrategyResultedInDescription=Merge of revisions {0} with base {1} using strategy {2} resulted in: {3}. {4} +mergeRecursiveReturnedNoCommit=Merge returned no commit:\n Depth {0}\n Head one {1}\n Head two {2} +mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}" +messageAndTaggerNotAllowedInUnannotatedTags = Unannotated tags cannot have a message or tagger +minutesAgo={0} minutes ago +missingAccesskey=Missing accesskey. +missingConfigurationForKey=No value for key {0} found in configuration +missingDeltaBase=delta base +missingForwardImageInGITBinaryPatch=Missing forward-image in GIT binary patch +missingObject=Missing {0} {1} +missingPrerequisiteCommits=missing prerequisite commits: +missingRequiredParameter=Parameter "{0}" is missing +missingSecretkey=Missing secretkey. +mixedStagesNotAllowed=Mixed stages not allowed +mkDirFailed=Creating directory {0} failed +mkDirsFailed=Creating directories for {0} failed +month=month +months=months +monthsAgo={0} months ago +multipleMergeBasesFor=Multiple merge bases for:\n {0}\n {1} found:\n {2}\n {3} +need2Arguments=Need 2 arguments +needPackOut=need packOut +needsAtLeastOneEntry=Needs at least one entry +needsWorkdir=Needs workdir +newlineInQuotesNotAllowed=Newline in quotes not allowed +noApplyInDelete=No apply in delete +noClosingBracket=No closing {0} found for {1} at index {2}. +noHEADExistsAndNoExplicitStartingRevisionWasSpecified=No HEAD exists and no explicit starting revision was specified +noHMACsupport=No {0} support: {1} +noMergeBase=No merge base could be determined. Reason={0}. {1} +noMergeHeadSpecified=No merge head specified +noSuchRef=no such ref +notABoolean=Not a boolean: {0} +notABundle=not a bundle +notADIRCFile=Not a DIRC file. +notAGitDirectory=not a git directory +notAPACKFile=Not a PACK file. +notARef=Not a ref: {0}: {1} +notASCIIString=Not ASCII string: {0} +notAuthorized=not authorized +notAValidPack=Not a valid pack {0} +notFound=not found. +nothingToFetch=Nothing to fetch. +nothingToPush=Nothing to push. +notMergedExceptionMessage=Branch was not deleted as it has not been merged yet; use the force option to delete it anyway +noXMLParserAvailable=No XML parser available. +objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream +objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree. +objectIsCorrupt=Object {0} is corrupt: {1} +objectIsNotA=Object {0} is not a {1}. +objectNotFound=Object {0} not found. +objectNotFoundIn=Object {0} not found in {1}. +obtainingCommitsForCherryPick=Obtaining commits that need to be cherry-picked +offsetWrittenDeltaBaseForObjectNotFoundInAPack=Offset-written delta base for object not found in a pack +onlyAlreadyUpToDateAndFastForwardMergesAreAvailable=only already-up-to-date and fast forward merges are available +onlyOneFetchSupported=Only one fetch supported +onlyOneOperationCallPerConnectionIsSupported=Only one operation call per connection is supported. +openFilesMustBeAtLeast1=Open files must be >= 1 +openingConnection=Opening connection +operationCanceled=Operation {0} was canceled +outputHasAlreadyBeenStarted=Output has already been started. +packChecksumMismatch=Pack checksum mismatch +packCorruptedWhileWritingToFilesystem=Pack corrupted while writing to filesystem +packDoesNotMatchIndex=Pack {0} does not match index +packetSizeMustBeAtLeast=packet size {0} must be >= {1} +packetSizeMustBeAtMost=packet size {0} must be <= {1} +packfileCorruptionDetected=Packfile corruption detected: {0} +packFileInvalid=Pack file invalid: {0} +packfileIsTruncated=Packfile is truncated. +packHasUnresolvedDeltas=pack has unresolved deltas +packingCancelledDuringObjectsWriting=Packing cancelled during objects writing +packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} +packRefs=Pack refs +packSizeNotSetYet=Pack size not yet set since it has not yet been received +packTooLargeForIndexVersion1=Pack too large for index version 1 +packWriterStatistics=Total {0,number,#0} (delta {1,number,#0}), reused {2,number,#0} (delta {3,number,#0}) +panicCantRenameIndexFile=Panic: index file {0} must be renamed to replace {1}; until then repository is corrupt +patchApplyException=Cannot apply: {0} +patchFormatException=Format error: {0} +pathIsNotInWorkingDir=Path is not in working dir +pathNotConfigured=Submodule path is not configured +peeledLineBeforeRef=Peeled line before ref. +peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph +prefixRemote=remote: +problemWithResolvingPushRefSpecsLocally=Problem with resolving push ref specs locally: {0} +progressMonUploading=Uploading {0} +propertyIsAlreadyNonNull=Property is already non null +pruneLoosePackedObjects=Prune loose objects also found in pack files +pruneLooseUnreferencedObjects=Prune loose, unreferenced objects +pullOnRepoWithoutHEADCurrentlyNotSupported=Pull on repository without HEAD currently not supported +pullTaskName=Pull +pushCancelled=push cancelled +pushIsNotSupportedForBundleTransport=Push is not supported for bundle transport +pushNotPermitted=push not permitted +rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry +readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0} +readTimedOut=Read timed out after {0} ms +receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes. +receivePackObjectTooLarge2=Object too large ({0} bytes), rejecting the pack. Max object size limit is {1} bytes. +receivePackInvalidLimit=Illegal limit parameter value {0} +receivePackTooLarge=Pack exceeds the limit of {0} bytes, rejecting the pack +receivingObjects=Receiving objects +refAlreadyExists=already exists +refAlreadyExists1=Ref {0} already exists +reflogEntryNotFound=Entry {0} not found in reflog for ''{1}'' +refNotResolved=Ref {0} can not be resolved +refUpdateReturnCodeWas=RefUpdate return code was: {0} +remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated +remoteDoesNotHaveSpec=Remote does not have {0} available for fetch. +remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push +remoteHungUpUnexpectedly=remote hung up unexpectedly +remoteNameCantBeNull=Remote name can't be null. +renameBranchFailedBecauseTag=Can not rename as Ref {0} is a tag +renameBranchFailedUnknownReason=Rename failed with unknown reason +renameBranchUnexpectedResult=Unexpected rename result {0} +renameFileFailed=Could not rename file {0} to {1} +renamesAlreadyFound=Renames have already been found. +renamesBreakingModifies=Breaking apart modified file pairs +renamesFindingByContent=Finding renames by content similarity +renamesFindingExact=Finding exact renames +renamesRejoiningModifies=Rejoining modified file pairs +repositoryAlreadyExists=Repository already exists: {0} +repositoryConfigFileInvalid=Repository config file {0} invalid {1} +repositoryIsRequired=Repository is required. +repositoryNotFound=repository not found: {0} +repositoryState_applyMailbox=Apply mailbox +repositoryState_bisecting=Bisecting +repositoryState_conflicts=Conflicts +repositoryState_merged=Merged +repositoryState_normal=Normal +repositoryState_rebase=Rebase +repositoryState_rebaseInteractive=Rebase interactive +repositoryState_rebaseOrApplyMailbox=Rebase/Apply mailbox +repositoryState_rebaseWithMerge=Rebase w/merge +requiredHashFunctionNotAvailable=Required hash function {0} not available. +resettingHead=Resetting head to {0} +resolvingDeltas=Resolving deltas +resultLengthIncorrect=result length incorrect +rewinding=Rewinding to commit {0} +searchForReuse=Finding sources +searchForSizes=Getting sizes +secondsAgo={0} seconds ago +selectingCommits=Selecting commits +sequenceTooLargeForDiffAlgorithm=Sequence too large for difference algorithm. +serviceNotEnabledNoName=Service not enabled +serviceNotPermitted={0} not permitted +serviceNotPermittedNoName=Service not permitted +shallowCommitsAlreadyInitialized=Shallow commits have already been initialized +shortCompressedStreamAt=Short compressed stream at {0} +shortReadOfBlock=Short read of block. +shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section. +shortSkipOfBlock=Short skip of block. +signingNotSupportedOnTag=Signing isn't supported on tag operations yet. +similarityScoreMustBeWithinBounds=Similarity score must be between 0 and 100. +sizeExceeds2GB=Path {0} size {1} exceeds 2 GiB limit. +skipMustBeNonNegative=skip must be >= 0 +smartHTTPPushDisabled=smart HTTP push disabled +sourceDestinationMustMatch=Source/Destination must match. +sourceIsNotAWildcard=Source is not a wildcard. +sourceRefDoesntResolveToAnyObject=Source ref {0} doesn't resolve to any object. +sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0} +squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD +staleRevFlagsOn=Stale RevFlags on {0} +startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported +stashApplyConflict=Applying stashed changes resulted in a conflict +stashApplyConflictInIndex=Applying stashed index changes resulted in a conflict. Dropped index changes. +stashApplyFailed=Applying stashed changes did not successfully complete +stashApplyOnUnsafeRepository=Cannot apply stashed commit on a repository with state: {0} +stashApplyWithoutHead=Cannot apply stashed commit in an empty repository or onto an unborn branch +stashCommitMissingTwoParents=Stashed commit ''{0}'' does not have two parent commits +stashDropDeleteRefFailed=Deleting stash reference failed with result: {0} +stashDropFailed=Dropping stashed commit failed +stashDropMissingReflog=Stash reflog does not contain entry ''{0}'' +stashFailed=Stashing local changes did not successfully complete +stashResolveFailed=Reference ''{0}'' does not resolve to stashed commit +statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled +submoduleExists=Submodule ''{0}'' already exists in the index +submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}'' +submodulesNotSupported=Submodules are not supported +symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java. +systemConfigFileInvalid=Systen wide config file {0} is invalid {1} +tagAlreadyExists=tag ''{0}'' already exists +tagNameInvalid=tag name {0} is invalid +tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported +theFactoryMustNotBeNull=The factory must not be null +timerAlreadyTerminated=Timer already terminated +topologicalSortRequired=Topological sort required. +transportExceptionBadRef=Empty ref: {0}: {1} +transportExceptionEmptyRef=Empty ref: {0} +transportExceptionInvalid=Invalid {0} {1}:{2} +transportExceptionMissingAssumed=Missing assumed {0} +transportExceptionReadRef=read {0} +transportNeedsRepository=Transport needs repository +transportProtoAmazonS3=Amazon S3 +transportProtoBundleFile=Git Bundle File +transportProtoFTP=FTP +transportProtoGitAnon=Anonymous Git +transportProtoHTTP=HTTP +transportProtoLocal=Local Git Repository +transportProtoSFTP=SFTP +transportProtoSSH=SSH +treeEntryAlreadyExists=Tree entry "{0}" already exists. +treeFilterMarkerTooManyFilters=Too many markTreeFilters passed, maximum number is {0} (passed {1}) +treeIteratorDoesNotSupportRemove=TreeIterator does not support remove() +treeWalkMustHaveExactlyTwoTrees=TreeWalk should have exactly two trees. +truncatedHunkLinesMissingForAncestor=Truncated hunk, at least {0} lines missing for ancestor {1} +truncatedHunkNewLinesMissing=Truncated hunk, at least {0} new lines is missing +truncatedHunkOldLinesMissing=Truncated hunk, at least {0} old lines is missing +tSizeMustBeGreaterOrEqual1=tSize must be >= 1 +unableToCheckConnectivity=Unable to check connectivity. +unableToStore=Unable to store {0}. +unableToWrite=Unable to write {0} +unencodeableFile=Unencodeable file: {0} +unexpectedCompareResult=Unexpected metadata comparison result: {0} +unexpectedEndOfConfigFile=Unexpected end of config file +unexpectedHunkTrailer=Unexpected hunk trailer +unexpectedOddResult=odd: {0} + {1} - {2} +unexpectedRefReport={0}: unexpected ref report: {1} +unexpectedReportLine=unexpected report line: {0} +unexpectedReportLine2={0} unexpected report line: {1} +unknownOrUnsupportedCommand=Unknown or unsupported command "{0}", only "{1}" is allowed. +unknownDIRCVersion=Unknown DIRC version {0} +unknownHost=unknown host +unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0} +unknownObject=unknown object +unknownObjectType=Unknown object type {0}. +unknownRepositoryFormat=Unknown repository format +unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0". +unknownZlibError=Unknown zlib error. +unmergedPath=Unmerged path: {0} +unmergedPaths=Repository contains unmerged paths +unpackException=Exception while parsing pack stream +unreadablePackIndex=Unreadable pack index: {0} +unrecognizedRef=Unrecognized ref: {0} +unsupportedArchiveFormat=Unknown archive format ''{0}'' +unsupportedCommand0=unsupported command 0 +unsupportedEncryptionAlgorithm=Unsupported encryption algorithm: {0} +unsupportedEncryptionVersion=Unsupported encryption version: {0} +unsupportedGC Unsupported garbage collector for repository type: {0} +unsupportedOperationNotAddAtEnd=Not add-at-end: {0} +unsupportedPackIndexVersion=Unsupported pack index version {0} +unsupportedPackVersion=Unsupported pack version {0}. +updatingReferences=Updating references +updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2} +uriNotConfigured=Submodule URI not configured +uriNotFound={0} not found +URINotSupported=URI not supported: {0} +URLNotFound={0} not found +userConfigFileInvalid=User config file {0} invalid {1} +walkFailure=Walk failure. +wantNotValid=want {0} not valid +weeksAgo={0} weeks ago +windowSizeMustBeLesserThanLimit=Window size must be < limit +windowSizeMustBePowerOf2=Window size must be power of 2 +writerAlreadyInitialized=Writer already initialized +writeTimedOut=Write timed out after {0} ms +writingNotPermitted=Writing not permitted +writingNotSupported=Writing {0} not supported. +writingObjects=Writing objects +wrongDecompressedLength=wrong decompressed length +wrongRepositoryState=Wrong Repository State: {0} +year=year +years=years +years0MonthsAgo={0} {1} ago +yearsAgo={0} years ago +yearsMonthsAgo={0} {1}, {2} {3} ago \ No newline at end of file diff --git a/src/test/java/org/jbake/app/GithubPublisherTest.java b/src/test/java/org/jbake/app/GithubPublisherTest.java new file mode 100644 index 000000000..2bbc441e5 --- /dev/null +++ b/src/test/java/org/jbake/app/GithubPublisherTest.java @@ -0,0 +1,140 @@ +package org.jbake.app; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.MapConfiguration; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.PersonIdent; +import org.jbake.launcher.LaunchOptions; +import org.jbake.publisher.GithubPublisher; +import org.jbake.spi.Publisher; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; + +public class GithubPublisherTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void publishContentToGhPagesBranch() throws IOException, GitAPIException { + + File currentDirectory = temporaryFolder.newFolder(); + File contentDirectory = new File(currentDirectory, "content"); + contentDirectory.mkdir(); + File contentFile = new File(contentDirectory, "a.html"); + + Files.write(contentFile.toPath(), "

Hello World

".getBytes()); + + Git git = GitUtil.initGit(currentDirectory); + GitUtil.addAndCommit(git, ".", "First commit"); + + CompositeConfiguration compositeConfiguration = new CompositeConfiguration(); + + Map configuration = new HashMap<>(); + configuration.put("git.user", "Alex"); + configuration.put("git.email", "alex@alex.com"); + + compositeConfiguration.append(new MapConfiguration(configuration)); + + LaunchOptions launchOptions = parseArguments(new String[] {currentDirectory.getAbsolutePath(), contentDirectory.getAbsolutePath()}); + Publisher githubPublisher = new GithubPublisher(); + githubPublisher.publish(compositeConfiguration, launchOptions); + + GitUtil.checkoutBranch(git, "gh-pages"); + assertThat(new File(currentDirectory, "a.html")).exists(); + + } + + @Test + public void publishContentToAlreadyCreatedGhPages() throws IOException, GitAPIException { + + File currentDirectory = temporaryFolder.newFolder(); + File contentDirectory = new File(currentDirectory, "content"); + contentDirectory.mkdir(); + File contentFile = new File(contentDirectory, "a.html"); + + Files.write(contentFile.toPath(), "

Hello World

".getBytes()); + + Git git = GitUtil.initGit(currentDirectory); + GitUtil.addAndCommit(git, ".", "First commit"); + + GitUtil.createOrphanBranch(git, "gh-pages", new PersonIdent("Alex", "Alex@alex.com")); + GitUtil.checkoutBranch(git, "gh-pages"); + Files.write(new File(currentDirectory, "b.html").toPath(), "

Hello World

".getBytes()); + GitUtil.addAndCommit(git, ".", "First Commit"); + + + CompositeConfiguration compositeConfiguration = new CompositeConfiguration(); + + Map configuration = new HashMap<>(); + configuration.put("git.user", "Alex"); + configuration.put("git.email", "alex@alex.com"); + + compositeConfiguration.append(new MapConfiguration(configuration)); + + + Publisher githubPublisher = new GithubPublisher(); + LaunchOptions launchOptions = parseArguments(new String[] {currentDirectory.getAbsolutePath(), contentDirectory.getAbsolutePath()}); + githubPublisher.publish(compositeConfiguration, launchOptions); + + GitUtil.checkoutBranch(git, "gh-pages"); + + assertThat(new File(currentDirectory, "a.html")).exists(); + } + + @Test + public void publishContentToGhPagesBranchWithDeepContent() throws IOException, GitAPIException { + + File currentDirectory = temporaryFolder.newFolder(); + File projectDirectory = new File(currentDirectory, "jbake"); + File contentDirectory = new File(projectDirectory, "content"); + contentDirectory.mkdirs(); + File contentFile = new File(contentDirectory, "a.html"); + + Files.write(contentFile.toPath(), "

Hello World

".getBytes()); + + Git git = GitUtil.initGit(currentDirectory); + GitUtil.addAndCommit(git, ".", "First commit"); + + CompositeConfiguration compositeConfiguration = new CompositeConfiguration(); + + Map configuration = new HashMap<>(); + configuration.put("git.user", "Alex"); + configuration.put("git.email", "alex@alex.com"); + + compositeConfiguration.append(new MapConfiguration(configuration)); + + Publisher githubPublisher = new GithubPublisher(); + LaunchOptions launchOptions = parseArguments(new String[] {currentDirectory.getAbsolutePath(), contentDirectory.getAbsolutePath()}); + githubPublisher.publish(compositeConfiguration, launchOptions); + + + GitUtil.checkoutBranch(git, "gh-pages"); + assertThat(new File(currentDirectory, "a.html")).exists(); + + } + + private LaunchOptions parseArguments(String[] args) { + LaunchOptions res = new LaunchOptions(); + CmdLineParser parser = new CmdLineParser(res); + + try { + parser.parseArgument(args); + } catch (CmdLineException e) { + } + + return res; + } +}