Imported the reference implementation contributed by syntevo which is used in their SmartGit product. You may create a bugtraq config section inf your .git/config file OR you may add a .gitbugtraq file to the root of your repository. Example: [bugtraq "issues"] url = http://code.google.com/p/gitblit/issues/detail?id=%BUGID% logRegex = "[Ii]ssue[-#:\\s]{1}\\d+" logRegex1 = "\\d+" [bugtraq "[pullrequests"] url = "https://github.com/gitblit/gitblit/pull/%BUGID%" logRegex = "(?:pull request|pull|pr)\\s*[-#]?([0-9]+)" Change-Id: Iaba305bf4280d08cc4d1abf533c2f1365470a43ftags/v1.4.0
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<classpath> | <classpath> | ||||
<classpathentry kind="src" path="src/main/java" /> | <classpathentry kind="src" path="src/main/java" /> | ||||
<classpathentry kind="src" path="src/main/bugtraq" /> | |||||
<classpathentry kind="src" path="src/test/java" output="bin/test-classes" /> | <classpathentry kind="src" path="src/test/java" output="bin/test-classes" /> | ||||
<classpathentry kind="src" path="src/test/bugtraq" output="bin/test-classes" /> | |||||
<classpathentry kind="src" path="src/main/resources" /> | <classpathentry kind="src" path="src/main/resources" /> | ||||
<classpathentry kind="lib" path="ext/dagger-1.1.0.jar" sourcepath="ext/src/dagger-1.1.0.jar" /> | <classpathentry kind="lib" path="ext/dagger-1.1.0.jar" sourcepath="ext/src/dagger-1.1.0.jar" /> | ||||
<classpathentry kind="lib" path="ext/javax.inject-1.jar" sourcepath="ext/src/javax.inject-1.jar" /> | <classpathentry kind="lib" path="ext/javax.inject-1.jar" sourcepath="ext/src/javax.inject-1.jar" /> | ||||
<classpathentry kind="lib" path="ext/dagger-compiler-1.1.0.jar" sourcepath="ext/src/dagger-compiler-1.1.0.jar" /> | <classpathentry kind="lib" path="ext/dagger-compiler-1.1.0.jar" sourcepath="ext/src/dagger-compiler-1.1.0.jar" /> | ||||
<classpathentry kind="lib" path="ext/javawriter-2.1.1.jar" sourcepath="ext/src/javawriter-2.1.1.jar" /> | <classpathentry kind="lib" path="ext/javawriter-2.1.1.jar" sourcepath="ext/src/javawriter-2.1.1.jar" /> | ||||
<classpathentry kind="lib" path="ext/annotations-12.0.jar" sourcepath="ext/src/annotations-12.0.jar" /> | |||||
<classpathentry kind="lib" path="ext/jcommander-1.17.jar" sourcepath="ext/src/jcommander-1.17.jar" /> | <classpathentry kind="lib" path="ext/jcommander-1.17.jar" sourcepath="ext/src/jcommander-1.17.jar" /> | ||||
<classpathentry kind="lib" path="ext/log4j-1.2.17.jar" sourcepath="ext/src/log4j-1.2.17.jar" /> | <classpathentry kind="lib" path="ext/log4j-1.2.17.jar" sourcepath="ext/src/log4j-1.2.17.jar" /> | ||||
<classpathentry kind="lib" path="ext/slf4j-api-1.6.6.jar" sourcepath="ext/src/slf4j-api-1.6.6.jar" /> | <classpathentry kind="lib" path="ext/slf4j-api-1.6.6.jar" sourcepath="ext/src/slf4j-api-1.6.6.jar" /> |
[bugtraq "issues"] | |||||
url = http://code.google.com/p/gitblit/issues/detail?id=%BUGID% | |||||
logRegex = "[Ii]ssue[-#:\\s]{1}\\d+" | |||||
logRegex1 = "\\d+" | |||||
[bugtraq "[pullrequests"] | |||||
url = "https://github.com/gitblit/gitblit/pull/%BUGID%" | |||||
logRegex = "(?:pull request|pull|pr)\\s*[-#]?([0-9]+)" |
# a scope to each directory. | # a scope to each directory. | ||||
sourceDirectories: | sourceDirectories: | ||||
- compile 'src/main/java' | - compile 'src/main/java' | ||||
- compile 'src/main/bugtraq' | |||||
- compile 'src/main/dagger' apt | - compile 'src/main/dagger' apt | ||||
- test 'src/test/java' | - test 'src/test/java' | ||||
- test 'src/test/bugtraq' | |||||
# Moxie supports one site-scoped directory for mx:doc | # Moxie supports one site-scoped directory for mx:doc | ||||
- site 'src/site' | - site 'src/site' | ||||
- compile 'com.squareup.dagger:dagger:1.1.0' :war apt | - compile 'com.squareup.dagger:dagger:1.1.0' :war apt | ||||
- compile 'com.squareup.dagger:dagger-compiler:1.1.0' :war optional apt | - compile 'com.squareup.dagger:dagger-compiler:1.1.0' :war optional apt | ||||
# Standard dependencies | # Standard dependencies | ||||
- compile 'com.intellij:annotations:12.0' :war | |||||
- compile 'com.beust:jcommander:1.17' :fedclient :authority | - compile 'com.beust:jcommander:1.17' :fedclient :authority | ||||
- compile 'log4j:log4j:1.2.17' :war :fedclient :authority | - compile 'log4j:log4j:1.2.17' :war :fedclient :authority | ||||
- compile 'org.slf4j:slf4j-api:1.6.6' :war :fedclient :authority | - compile 'org.slf4j:slf4j-api:1.6.6' :war :fedclient :authority |
<exclude-output /> | <exclude-output /> | ||||
<content url="file://$MODULE_DIR$"> | <content url="file://$MODULE_DIR$"> | ||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | ||||
<sourceFolder url="file://$MODULE_DIR$/src/main/bugtraq" isTestSource="false" /> | |||||
<sourceFolder url="file://$MODULE_DIR$/src/main/dagger" isTestSource="false" /> | <sourceFolder url="file://$MODULE_DIR$/src/main/dagger" isTestSource="false" /> | ||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> | <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> | ||||
<sourceFolder url="file://$MODULE_DIR$/src/test/bugtraq" isTestSource="true" /> | |||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" /> | <sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" /> | ||||
</content> | </content> | ||||
<orderEntry type="sourceFolder" forTests="false" /> | <orderEntry type="sourceFolder" forTests="false" /> | ||||
</SOURCES> | </SOURCES> | ||||
</library> | </library> | ||||
</orderEntry> | </orderEntry> | ||||
<orderEntry type="module-library"> | |||||
<library name="annotations-12.0.jar"> | |||||
<CLASSES> | |||||
<root url="jar://$MODULE_DIR$/ext/annotations-12.0.jar!/" /> | |||||
</CLASSES> | |||||
<JAVADOC /> | |||||
<SOURCES> | |||||
<root url="jar://$MODULE_DIR$/ext/src/annotations-12.0.jar!/" /> | |||||
</SOURCES> | |||||
</library> | |||||
</orderEntry> | |||||
<orderEntry type="module-library"> | <orderEntry type="module-library"> | ||||
<library name="jcommander-1.17.jar"> | <library name="jcommander-1.17.jar"> | ||||
<CLASSES> | <CLASSES> |
- Added a normalized diffstat display to the commit, commitdiff, and compare pages | - Added a normalized diffstat display to the commit, commitdiff, and compare pages | ||||
- Added GO setting to automatically redirect all http requests to the secure https connector | - Added GO setting to automatically redirect all http requests to the secure https connector | ||||
- Automatically display common repository root documents as tabs on the docs page | - Automatically display common repository root documents as tabs on the docs page | ||||
- Support bugtraq configuration in collaboration with syntevo | |||||
dependencyChanges: | dependencyChanges: | ||||
- updated to Jetty 8.1.13 | - updated to Jetty 8.1.13 | ||||
- updated to JGit 3.1.0 | - updated to JGit 3.1.0 | ||||
- fpeters.fae | - fpeters.fae | ||||
- David Ostrovsky | - David Ostrovsky | ||||
- Alex Lewis | - Alex Lewis | ||||
- Marc Strapetz | |||||
} | } | ||||
# | # |
Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
Redistribution and use in source and binary forms, with or without | |||||
modification, are permitted provided that the following conditions are met: | |||||
o Redistributions of source code must retain the above copyright notice, | |||||
this list of conditions and the following disclaimer. | |||||
o Redistributions in binary form must reproduce the above copyright notice, | |||||
this list of conditions and the following disclaimer in the documentation | |||||
and/or other materials provided with the distribution. | |||||
o Neither the name of syntevo GmbH nor the names of | |||||
its contributors may be used to endorse or promote products derived | |||||
from this software without specific prior written permission. | |||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
Third Parties | |||||
------------- | |||||
The following third parties have rights on parts of the SOFTWARE: | |||||
- IDEA annotations.jar, copyright by JetBrains, Inc. | |||||
- JGit, copyright by various authors (http://repo.or.cz/w/jgit.git and | |||||
http://jgit.org). | |||||
The corresponding license agreement can be found at | |||||
http://repo.or.cz/w/jgit.git/blob/HEAD:/LICENSE. | |||||
- JUnit, copyright by www.hamcrest.org. | |||||
The corresponding license agreement can be found at | |||||
in subdirectory lib/JUNIT-LICENSE. |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.HashSet; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
import org.eclipse.jgit.errors.ConfigInvalidException; | |||||
import org.eclipse.jgit.lib.Config; | |||||
import org.eclipse.jgit.lib.Constants; | |||||
import org.eclipse.jgit.lib.FileMode; | |||||
import org.eclipse.jgit.lib.ObjectId; | |||||
import org.eclipse.jgit.lib.ObjectLoader; | |||||
import org.eclipse.jgit.lib.Repository; | |||||
import org.eclipse.jgit.lib.StoredConfig; | |||||
import org.eclipse.jgit.revwalk.RevCommit; | |||||
import org.eclipse.jgit.revwalk.RevObject; | |||||
import org.eclipse.jgit.revwalk.RevTree; | |||||
import org.eclipse.jgit.revwalk.RevWalk; | |||||
import org.eclipse.jgit.storage.file.FileBasedConfig; | |||||
import org.eclipse.jgit.treewalk.TreeWalk; | |||||
import org.eclipse.jgit.treewalk.filter.PathFilterGroup; | |||||
import org.jetbrains.annotations.NotNull; | |||||
import org.jetbrains.annotations.Nullable; | |||||
public final class BugtraqConfig { | |||||
// Constants ============================================================== | |||||
private static final String DOT_GIT_BUGTRAQ = ".gitbugtraq"; | |||||
private static final String BUGTRAQ = "bugtraq"; | |||||
private static final String URL = "url"; | |||||
private static final String ENABLED = "enabled"; | |||||
private static final String LOG_REGEX = "logRegex"; | |||||
// Static ================================================================= | |||||
@Nullable | |||||
public static BugtraqConfig read(@NotNull Repository repository) throws IOException, ConfigInvalidException { | |||||
final Config baseConfig = getBaseConfig(repository); | |||||
final Set<String> allNames = new HashSet<String>(); | |||||
final Config config = repository.getConfig(); | |||||
allNames.addAll(config.getSubsections(BUGTRAQ)); | |||||
if (baseConfig != null) { | |||||
allNames.addAll(baseConfig.getSubsections(BUGTRAQ)); | |||||
} | |||||
final List<BugtraqEntry> entries = new ArrayList<BugtraqEntry>(); | |||||
for (String name : allNames) { | |||||
final String url = getString(name, URL, config, baseConfig); | |||||
final String enabled = getString(name, ENABLED, config, baseConfig); | |||||
if (enabled != null && !"true".equals(enabled)) { | |||||
continue; | |||||
} | |||||
final String logIdRegex = getString(name, LOG_REGEX, config, baseConfig); | |||||
if (url == null || logIdRegex == null) { | |||||
return null; | |||||
} | |||||
final List<String> logIdRegexs = new ArrayList<String>(); | |||||
logIdRegexs.add(logIdRegex); | |||||
for (int index = 1; index < Integer.MAX_VALUE; index++) { | |||||
final String logIdRegexN = getString(name, LOG_REGEX + index, config, baseConfig); | |||||
if (logIdRegexN == null) { | |||||
break; | |||||
} | |||||
logIdRegexs.add(logIdRegexN); | |||||
} | |||||
entries.add(new BugtraqEntry(url, logIdRegexs)); | |||||
} | |||||
if (entries.isEmpty()) { | |||||
return null; | |||||
} | |||||
return new BugtraqConfig(entries); | |||||
} | |||||
// Fields ================================================================= | |||||
@NotNull | |||||
private final List<BugtraqEntry> entries; | |||||
// Setup ================================================================== | |||||
BugtraqConfig(@NotNull List<BugtraqEntry> entries) { | |||||
this.entries = entries; | |||||
} | |||||
// Accessing ============================================================== | |||||
@NotNull | |||||
public List<BugtraqEntry> getEntries() { | |||||
return Collections.unmodifiableList(entries); | |||||
} | |||||
// Utils ================================================================== | |||||
@Nullable | |||||
private static Config getBaseConfig(Repository repository) throws IOException, ConfigInvalidException { | |||||
final Config baseConfig; | |||||
if (repository.isBare()) { | |||||
// read bugtraq config directly from the repository | |||||
String content = null; | |||||
String head = repository.getFullBranch(); | |||||
RevWalk rw = new RevWalk(repository); | |||||
TreeWalk tw = new TreeWalk(repository); | |||||
tw.setFilter(PathFilterGroup.createFromStrings(DOT_GIT_BUGTRAQ)); | |||||
try { | |||||
ObjectId headId = repository.resolve(head); | |||||
RevCommit commit = rw.parseCommit(headId); | |||||
RevTree tree = commit.getTree(); | |||||
tw.reset(tree); | |||||
while (tw.next()) { | |||||
if (tw.isSubtree()) { | |||||
tw.enterSubtree(); | |||||
continue; | |||||
} | |||||
ObjectId entid = tw.getObjectId(0); | |||||
FileMode entmode = tw.getFileMode(0); | |||||
if (entmode == FileMode.REGULAR_FILE) { | |||||
RevObject ro = rw.lookupAny(entid, entmode.getObjectType()); | |||||
rw.parseBody(ro); | |||||
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||||
ObjectLoader ldr = repository.open(ro.getId(), Constants.OBJ_BLOB); | |||||
byte[] tmp = new byte[4096]; | |||||
InputStream in = ldr.openStream(); | |||||
int n; | |||||
while ((n = in.read(tmp)) > 0) { | |||||
os.write(tmp, 0, n); | |||||
} | |||||
in.close(); | |||||
content = new String(os.toByteArray(), commit.getEncoding()); | |||||
} | |||||
} | |||||
} finally { | |||||
rw.dispose(); | |||||
tw.release(); | |||||
} | |||||
if (content == null) { | |||||
// config not found | |||||
baseConfig = null; | |||||
} else { | |||||
// parse the config | |||||
Config cfg = new Config(); | |||||
cfg.fromText(content); | |||||
baseConfig = new StoredConfig(cfg) { | |||||
@Override | |||||
public void save() throws IOException { | |||||
} | |||||
@Override | |||||
public void load() throws IOException, ConfigInvalidException { | |||||
} | |||||
}; | |||||
} | |||||
} else { | |||||
// read bugtraq config from work tree | |||||
final File baseFile = new File(repository.getWorkTree(), DOT_GIT_BUGTRAQ); | |||||
if (baseFile.isFile()) { | |||||
FileBasedConfig fileConfig = new FileBasedConfig(baseFile, repository.getFS()); | |||||
fileConfig.load(); | |||||
baseConfig = fileConfig; | |||||
} | |||||
else { | |||||
baseConfig = null; | |||||
} | |||||
} | |||||
return baseConfig; | |||||
} | |||||
@Nullable | |||||
private static String getString(@NotNull String subsection, @NotNull String key, @NotNull Config config, @Nullable Config baseConfig) { | |||||
final String value = config.getString(BUGTRAQ, subsection, key); | |||||
if (value != null) { | |||||
return trimMaybeNull(value); | |||||
} | |||||
if (baseConfig != null) { | |||||
return trimMaybeNull(baseConfig.getString(BUGTRAQ, subsection, key)); | |||||
} | |||||
return value; | |||||
} | |||||
@Nullable | |||||
private static String trimMaybeNull(@Nullable String string) { | |||||
if (string == null) { | |||||
return null; | |||||
} | |||||
string = string.trim(); | |||||
if (string.length() == 0) { | |||||
return null; | |||||
} | |||||
return string; | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import java.util.*; | |||||
import org.jetbrains.annotations.*; | |||||
final class BugtraqEntry { | |||||
// Fields ================================================================= | |||||
private final String url; | |||||
private final BugtraqParser parser; | |||||
// Setup ================================================================== | |||||
public BugtraqEntry(@NotNull String url, @NotNull List<String> logIdRegexs) throws BugtraqException { | |||||
this.url = url; | |||||
this.parser = BugtraqParser.createInstance(logIdRegexs); | |||||
} | |||||
// Accessing ============================================================== | |||||
@NotNull | |||||
public String getUrl() { | |||||
return url; | |||||
} | |||||
@NotNull | |||||
public BugtraqParser getParser() { | |||||
return parser; | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import java.io.*; | |||||
public class BugtraqException extends IOException { | |||||
// Setup ================================================================== | |||||
public BugtraqException(String message) { | |||||
super(message); | |||||
} | |||||
public BugtraqException(String message, Throwable cause) { | |||||
super(message, cause); | |||||
} | |||||
public BugtraqException(Throwable cause) { | |||||
super(cause); | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import java.util.*; | |||||
import org.jetbrains.annotations.*; | |||||
public final class BugtraqFormatter { | |||||
// Fields ================================================================= | |||||
private final BugtraqConfig config; | |||||
// Setup ================================================================== | |||||
public BugtraqFormatter(@NotNull BugtraqConfig config) { | |||||
this.config = config; | |||||
} | |||||
// Accessing ============================================================== | |||||
public void formatLogMessage(@NotNull String message, @NotNull OutputHandler outputHandler) { | |||||
final SortedSet<IssueId> allIds = new TreeSet<IssueId>(new Comparator<IssueId>() { | |||||
@Override | |||||
public int compare(IssueId o1, IssueId o2) { | |||||
final int from1 = o1.id.getFrom(); | |||||
final int from2 = o2.id.getFrom(); | |||||
return from1 > from2 ? +1 : from1 < from2 ? -1 : 0; | |||||
} | |||||
}); | |||||
for (BugtraqEntry entry : config.getEntries()) { | |||||
final List<BugtraqParserIssueId> ids = entry.getParser().parse(message); | |||||
if (ids == null) { | |||||
continue; | |||||
} | |||||
for (BugtraqParserIssueId id : ids) { | |||||
allIds.add(new IssueId(entry, id)); | |||||
} | |||||
} | |||||
int lastIdEnd = -1; | |||||
for (IssueId issueId : allIds) { | |||||
final BugtraqParserIssueId id = issueId.id; | |||||
if (id.getFrom() <= lastIdEnd) { | |||||
continue; | |||||
} | |||||
appendText(message.substring(lastIdEnd + 1, id.getFrom()), outputHandler); | |||||
final String linkText = message.substring(id.getFrom(), id.getTo() + 1); | |||||
final String target = issueId.entry.getUrl().replace("%BUGID%", id.getId()); | |||||
outputHandler.appendLink(linkText, target); | |||||
lastIdEnd = id.getTo(); | |||||
} | |||||
if (lastIdEnd - 1 < message.length()) { | |||||
appendText(message.substring(lastIdEnd + 1, message.length()), outputHandler); | |||||
} | |||||
} | |||||
// Utils ================================================================== | |||||
private static void appendText(@NotNull String message, @NotNull OutputHandler outputHandler) { | |||||
if (message.length() == 0) { | |||||
return; | |||||
} | |||||
outputHandler.appendText(message); | |||||
} | |||||
// Inner Classes ========================================================== | |||||
public interface OutputHandler { | |||||
void appendText(@NotNull String text); | |||||
void appendLink(@NotNull String name, @NotNull String target); | |||||
} | |||||
private static class IssueId { | |||||
private final BugtraqEntry entry; | |||||
private final BugtraqParserIssueId id; | |||||
private IssueId(BugtraqEntry entry, BugtraqParserIssueId id) { | |||||
this.entry = entry; | |||||
this.id = id; | |||||
} | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import java.util.*; | |||||
import java.util.regex.*; | |||||
import org.jetbrains.annotations.*; | |||||
final class BugtraqParser { | |||||
// Static ================================================================= | |||||
@NotNull | |||||
public static BugtraqParser createInstance(@NotNull List<String> regexs) throws BugtraqException { | |||||
try { | |||||
return new BugtraqParser(regexs); | |||||
} | |||||
catch (PatternSyntaxException ex) { | |||||
throw new BugtraqException(ex); | |||||
} | |||||
} | |||||
// Fields ================================================================= | |||||
private final List<Pattern> patterns; | |||||
// Setup ================================================================== | |||||
private BugtraqParser(List<String> regexs) { | |||||
this.patterns = new ArrayList<Pattern>(); | |||||
for (String regex : regexs) { | |||||
patterns.add(compilePatternSafe(regex)); | |||||
} | |||||
} | |||||
// Accessing ============================================================== | |||||
@Nullable | |||||
public List<BugtraqParserIssueId> parse(@NotNull String message) { | |||||
List<Part> parts = new ArrayList<Part>(); | |||||
parts.add(new Part(message, 0, message.length() - 1)); | |||||
boolean firstMatch = false; | |||||
for (Pattern pattern : patterns) { | |||||
final List<Part> newParts = new ArrayList<Part>(); | |||||
for (Part part : parts) { | |||||
final Matcher matcher = pattern.matcher(part.text); | |||||
while (matcher.find()) { | |||||
firstMatch = true; | |||||
if (matcher.groupCount() == 0) { | |||||
addNewPart(part, matcher, 0, newParts); | |||||
} | |||||
else { | |||||
addNewPart(part, matcher, 1, newParts); | |||||
} | |||||
} | |||||
} | |||||
parts = newParts; | |||||
if (parts.isEmpty()) { | |||||
parts = null; | |||||
break; | |||||
} | |||||
} | |||||
if (!firstMatch) { | |||||
return null; | |||||
} | |||||
if (parts == null) { | |||||
parts = new ArrayList<Part>(); | |||||
} | |||||
final List<BugtraqParserIssueId> ids = new ArrayList<BugtraqParserIssueId>(); | |||||
for (Part part : parts) { | |||||
final BugtraqParserIssueId id = new BugtraqParserIssueId(part.from, part.to, part.text); | |||||
if (ids.size() > 0) { | |||||
final BugtraqParserIssueId lastId = ids.get(ids.size() - 1); | |||||
if (id.getFrom() <= lastId.getTo()) { | |||||
continue; | |||||
} | |||||
} | |||||
ids.add(id); | |||||
} | |||||
return ids; | |||||
} | |||||
// Utils ================================================================== | |||||
private static void addNewPart(Part part, Matcher matcher, int group, List<Part> newParts) { | |||||
final int textStart = matcher.start(group) + part.from; | |||||
final int textEnd = matcher.end(group) - 1 + part.from; | |||||
if (textEnd < 0) { | |||||
return; | |||||
} | |||||
final Part newPart = new Part(matcher.group(group), textStart, textEnd); | |||||
newParts.add(newPart); | |||||
} | |||||
private static Pattern compilePatternSafe(String pattern) throws PatternSyntaxException { | |||||
return Pattern.compile(pattern); | |||||
} | |||||
// Inner Classes ========================================================== | |||||
private static class Part { | |||||
private final int from; | |||||
private final int to; | |||||
private final String text; | |||||
public Part(String text, int from, int to) { | |||||
this.text = text; | |||||
this.from = from; | |||||
this.to = to; | |||||
} | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
final class BugtraqParserIssueId { | |||||
// Fields ================================================================= | |||||
private final int from; | |||||
private final int to; | |||||
private final String id; | |||||
// Setup ================================================================== | |||||
public BugtraqParserIssueId(int from, int to, String id) { | |||||
this.id = id; | |||||
this.from = from; | |||||
this.to = to; | |||||
} | |||||
// Accessing ============================================================== | |||||
public int getFrom() { | |||||
return from; | |||||
} | |||||
public int getTo() { | |||||
return to; | |||||
} | |||||
public String getId() { | |||||
return id; | |||||
} | |||||
} |
StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName()); | StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName()); | ||||
entry.published = commit.getCommitterIdent().getWhen(); | entry.published = commit.getCommitterIdent().getWhen(); | ||||
entry.contentType = "text/html"; | entry.contentType = "text/html"; | ||||
String message = processor.processCommitMessage(model, commit.getFullMessage()); | |||||
String message = processor.processCommitMessage(repository, model, commit.getFullMessage()); | |||||
entry.content = message; | entry.content = message; | ||||
entry.repository = model.name; | entry.repository = model.name; | ||||
entry.branch = objectId; | entry.branch = objectId; |
*/ | */ | ||||
package com.gitblit.utils; | package com.gitblit.utils; | ||||
import java.io.IOException; | |||||
import java.text.MessageFormat; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Map.Entry; | import java.util.Map.Entry; | ||||
import org.eclipse.jgit.errors.ConfigInvalidException; | |||||
import org.eclipse.jgit.lib.Repository; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import com.gitblit.IStoredSettings; | import com.gitblit.IStoredSettings; | ||||
import com.gitblit.Keys; | import com.gitblit.Keys; | ||||
import com.gitblit.models.RepositoryModel; | import com.gitblit.models.RepositoryModel; | ||||
import com.syntevo.bugtraq.BugtraqConfig; | |||||
import com.syntevo.bugtraq.BugtraqFormatter; | |||||
import com.syntevo.bugtraq.BugtraqFormatter.OutputHandler; | |||||
public class MessageProcessor { | public class MessageProcessor { | ||||
* This method uses the preferred renderer to transform the commit message. | * This method uses the preferred renderer to transform the commit message. | ||||
* | * | ||||
* @param repository | * @param repository | ||||
* @param model | |||||
* @param text | * @param text | ||||
* @return html version of the commit message | * @return html version of the commit message | ||||
*/ | */ | ||||
public String processCommitMessage(RepositoryModel repository, String text) { | |||||
switch (repository.commitMessageRenderer) { | |||||
public String processCommitMessage(Repository repository, RepositoryModel model, String text) { | |||||
switch (model.commitMessageRenderer) { | |||||
case MARKDOWN: | case MARKDOWN: | ||||
try { | try { | ||||
String prepared = processCommitMessageRegex(repository.name, text); | |||||
String prepared = processCommitMessageRegex(repository, model.name, text); | |||||
return MarkdownUtils.transformMarkdown(prepared); | return MarkdownUtils.transformMarkdown(prepared); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
logger.error("Failed to render commit message as markdown", e); | logger.error("Failed to render commit message as markdown", e); | ||||
break; | break; | ||||
} | } | ||||
return processPlainCommitMessage(repository.name, text); | |||||
return processPlainCommitMessage(repository, model.name, text); | |||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* This method assumes the commit message is plain text. | * This method assumes the commit message is plain text. | ||||
* | * | ||||
* @param repository | |||||
* @param repositoryName | * @param repositoryName | ||||
* @param text | * @param text | ||||
* @return html version of the commit message | * @return html version of the commit message | ||||
*/ | */ | ||||
public String processPlainCommitMessage(String repositoryName, String text) { | |||||
public String processPlainCommitMessage(Repository repository, String repositoryName, String text) { | |||||
String html = StringUtils.escapeForHtml(text, false); | String html = StringUtils.escapeForHtml(text, false); | ||||
html = processCommitMessageRegex(repositoryName, html); | |||||
html = processCommitMessageRegex(repository, repositoryName, html); | |||||
return StringUtils.breakLinesForHtml(html); | return StringUtils.breakLinesForHtml(html); | ||||
} | } | ||||
* Apply globally or per-repository specified regex substitutions to the | * Apply globally or per-repository specified regex substitutions to the | ||||
* commit message. | * commit message. | ||||
* | * | ||||
* @param repository | |||||
* @param repositoryName | * @param repositoryName | ||||
* @param text | * @param text | ||||
* @return the processed commit message | * @return the processed commit message | ||||
*/ | */ | ||||
protected String processCommitMessageRegex(String repositoryName, String text) { | |||||
protected String processCommitMessageRegex(Repository repository, String repositoryName, String text) { | |||||
Map<String, String> map = new HashMap<String, String>(); | Map<String, String> map = new HashMap<String, String>(); | ||||
// global regex keys | // global regex keys | ||||
if (settings.getBoolean(Keys.regex.global, false)) { | if (settings.getBoolean(Keys.regex.global, false)) { | ||||
+ definition); | + definition); | ||||
} | } | ||||
} | } | ||||
try { | |||||
// parse bugtraq repo config | |||||
BugtraqConfig config = BugtraqConfig.read(repository); | |||||
if (config != null) { | |||||
BugtraqFormatter formatter = new BugtraqFormatter(config); | |||||
StringBuilder sb = new StringBuilder(); | |||||
formatter.formatLogMessage(text, new BugtraqOutputHandler(sb)); | |||||
text = sb.toString(); | |||||
} | |||||
} catch (IOException e) { | |||||
logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); | |||||
} catch (ConfigInvalidException e) { | |||||
logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); | |||||
} | |||||
return text; | return text; | ||||
} | } | ||||
private class BugtraqOutputHandler implements OutputHandler { | |||||
final StringBuilder sb; | |||||
BugtraqOutputHandler(StringBuilder sb) { | |||||
this.sb = sb; | |||||
} | |||||
@Override | |||||
public void appendText(String text) { | |||||
sb.append(text); | |||||
} | |||||
@Override | |||||
public void appendLink(String name, String target) { | |||||
sb.append(MessageFormat.format("<a class=\"bugtraq\" href=\"{1}\">{0}</a>", name, target)); | |||||
} | |||||
} | |||||
} | } |
item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent())); | item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent())); | ||||
item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef | item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef | ||||
.getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils())); | .getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils())); | ||||
item.add(new Label("noteContent", messageProcessor().processPlainCommitMessage(repositoryName, | |||||
item.add(new Label("noteContent", messageProcessor().processPlainCommitMessage(getRepository(), repositoryName, | |||||
entry.content)).setEscapeModelStrings(false)); | entry.content)).setEscapeModelStrings(false)); | ||||
} | } | ||||
}; | }; |
item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent())); | item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent())); | ||||
item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef | item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef | ||||
.getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils())); | .getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils())); | ||||
item.add(new Label("noteContent", messageProcessor().processPlainCommitMessage(repositoryName, | |||||
item.add(new Label("noteContent", messageProcessor().processPlainCommitMessage(getRepository(), repositoryName, | |||||
entry.content)).setEscapeModelStrings(false)); | entry.content)).setEscapeModelStrings(false)); | ||||
} | } | ||||
}; | }; | ||||
.newPathParameter(repositoryName, entry.commitId, path))); | .newPathParameter(repositoryName, entry.commitId, path))); | ||||
} | } | ||||
// quick links | // quick links | ||||
if (entry.isSubmodule()) { | if (entry.isSubmodule()) { | ||||
item.add(new ExternalLink("raw", "").setEnabled(false)); | item.add(new ExternalLink("raw", "").setEnabled(false)); | ||||
// submodule | // submodule | ||||
item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils | item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils | ||||
.newPathParameter(repositoryName, entry.commitId, entry.path)) | .newPathParameter(repositoryName, entry.commitId, entry.path)) |
protected void addFullText(String wicketId, String text) { | protected void addFullText(String wicketId, String text) { | ||||
RepositoryModel model = getRepositoryModel(); | RepositoryModel model = getRepositoryModel(); | ||||
String content = messageProcessor().processCommitMessage(model, text); | |||||
String content = messageProcessor().processCommitMessage(r, model, text); | |||||
String html; | String html; | ||||
switch (model.commitMessageRenderer) { | switch (model.commitMessageRenderer) { | ||||
case MARKDOWN: | case MARKDOWN: |
vertical-align: text-bottom; | vertical-align: text-bottom; | ||||
} | } | ||||
a.bugtraq { | |||||
font-weight: bold; | |||||
} | |||||
[class^="icon-"], [class*=" icon-"] i { | [class^="icon-"], [class*=" icon-"] i { | ||||
/* override for a links that look like bootstrap buttons */ | /* override for a links that look like bootstrap buttons */ | ||||
vertical-align: text-bottom; | vertical-align: text-bottom; |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import junit.framework.*; | |||||
import java.util.*; | |||||
import org.jetbrains.annotations.*; | |||||
public class BugtraqFormatterTest extends TestCase { | |||||
// Accessing ============================================================== | |||||
public void testSimple() throws BugtraqException { | |||||
final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/%BUGID%", "JRA-\\d+")); | |||||
doTest(formatter, "JRA-7399: Email subject formatting", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(": Email subject formatting")); | |||||
doTest(formatter, " JRA-7399, JRA-7398: Email subject formatting", t(" "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", "), l("JRA-7398", "https://jira.atlassian.com/browse/JRA-7398"), t(": Email subject formatting")); | |||||
doTest(formatter, "Fixed JRA-7399", t("Fixed "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399")); | |||||
} | |||||
public void testTwoNonIntersectingConfigurations() throws BugtraqException { | |||||
final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/%BUGID%", "JRA-\\d+"), | |||||
createEntry("https://issues.apache.org/jira/browse/%BUGID%", "VELOCITY-\\d+")); | |||||
doTest(formatter, "JRA-7399, VELOCITY-847: fix", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", "), l("VELOCITY-847", "https://issues.apache.org/jira/browse/VELOCITY-847"), t(": fix")); | |||||
doTest(formatter, " JRA-7399: fix/VELOCITY-847", t(" "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(": fix/"), l("VELOCITY-847", "https://issues.apache.org/jira/browse/VELOCITY-847")); | |||||
doTest(formatter, "JRA-7399VELOCITY-847", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), l("VELOCITY-847", "https://issues.apache.org/jira/browse/VELOCITY-847")); | |||||
} | |||||
public void testTwoIntersectingConfigurations() throws BugtraqException { | |||||
final BugtraqFormatter formatter = createFormatter(createEntry("https://host1/%BUGID%", "A[AB]"), | |||||
createEntry("https://host2/%BUGID%", "BA[A]?")); | |||||
doTest(formatter, "AA: fix", l("AA", "https://host1/AA"), t(": fix")); | |||||
doTest(formatter, "AB: fix", l("AB", "https://host1/AB"), t(": fix")); | |||||
doTest(formatter, "BA: fix", l("BA", "https://host2/BA"), t(": fix")); | |||||
doTest(formatter, "BAA: fix", l("BAA", "https://host2/BAA"), t(": fix")); | |||||
doTest(formatter, "BAAA: fix", l("BAA", "https://host2/BAA"), t("A: fix")); | |||||
doTest(formatter, "BAAAA: fix", l("BAA", "https://host2/BAA"), l("AA", "https://host1/AA"), t(": fix")); | |||||
doTest(formatter, "BAAAAA: fix", l("BAA", "https://host2/BAA"), l("AA", "https://host1/AA"), t("A: fix")); | |||||
doTest(formatter, "BAAABA: fix", l("BAA", "https://host2/BAA"), l("AB", "https://host1/AB"), t("A: fix")); | |||||
doTest(formatter, "BAAABAA: fix", l("BAA", "https://host2/BAA"), l("AB", "https://host1/AB"), l("AA", "https://host1/AA"), t(": fix")); | |||||
doTest(formatter, "BAAB: fix", l("BAA", "https://host2/BAA"), t("B: fix")); | |||||
doTest(formatter, "BAAAB: fix", l("BAA", "https://host2/BAA"), l("AB", "https://host1/AB"), t(": fix")); | |||||
doTest(formatter, "BAABBA: fix", l("BAA", "https://host2/BAA"), t("B"), l("BA", "https://host2/BA"), t(": fix")); | |||||
} | |||||
// Utils ================================================================== | |||||
private BugtraqFormatter createFormatter(BugtraqEntry ... entries) { | |||||
return new BugtraqFormatter(new BugtraqConfig(Arrays.asList(entries))); | |||||
} | |||||
private BugtraqEntry createEntry(String url, String ... logRegexs) throws BugtraqException { | |||||
return new BugtraqEntry(url, Arrays.asList(logRegexs)); | |||||
} | |||||
private Text t(String text) { | |||||
return new Text(text); | |||||
} | |||||
private Link l(String text, String url) { | |||||
return new Link(text, url); | |||||
} | |||||
private void doTest(BugtraqFormatter formatter, String message, Atom ... expectedAtoms) { | |||||
final List<Atom> actualAtoms = new ArrayList<Atom>(); | |||||
formatter.formatLogMessage(message, new BugtraqFormatter.OutputHandler() { | |||||
@Override | |||||
public void appendText(@NotNull String text) { | |||||
actualAtoms.add(t(text)); | |||||
} | |||||
@Override | |||||
public void appendLink(@NotNull String name, @NotNull String target) { | |||||
actualAtoms.add(l(name, target)); | |||||
} | |||||
}); | |||||
assertEquals(Arrays.asList(expectedAtoms), actualAtoms); | |||||
} | |||||
// Inner Classes ========================================================== | |||||
private static interface Atom { | |||||
} | |||||
private static class Text implements Atom { | |||||
private final String text; | |||||
private Text(String text) { | |||||
this.text = text; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return text; | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return text.hashCode(); | |||||
} | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if (obj == null || obj.getClass() != getClass()) { | |||||
return false; | |||||
} | |||||
return text.equals(((Text)obj).text); | |||||
} | |||||
} | |||||
private static class Link implements Atom { | |||||
private final String text; | |||||
private final String url; | |||||
private Link(String text, String url) { | |||||
this.text = text; | |||||
this.url = url; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "(" + text + "," + url + ")"; | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return text.hashCode() ^ url.hashCode(); | |||||
} | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if (obj == null || obj.getClass() != getClass()) { | |||||
return false; | |||||
} | |||||
return text.equals(((Link)obj).text) | |||||
&& url.equals(((Link)obj).url); | |||||
} | |||||
} | |||||
} |
/* | |||||
* Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* o Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* | |||||
* o Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* | |||||
* o Neither the name of syntevo GmbH nor the names of | |||||
* its contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package com.syntevo.bugtraq; | |||||
import junit.framework.*; | |||||
import java.util.*; | |||||
public class BugtraqParserTest extends TestCase { | |||||
// Accessing ============================================================== | |||||
public void testSimple1() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("\\d"); | |||||
assertNull(parser.parse("")); | |||||
doTest("1", parser, id(0, 0, "1")); | |||||
doTest("1 2 3", parser, id(0, 0, "1"), id(2, 2, "2"), id(4, 4, "3")); | |||||
} | |||||
public void testSimple2() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("(\\d)"); | |||||
assertNull(parser.parse("")); | |||||
doTest("1", parser, id(0, 0, "1")); | |||||
doTest("1 2 3", parser, id(0, 0, "1"), id(2, 2, "2"), id(4, 4, "3")); | |||||
} | |||||
public void testSimple3() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("(SG-\\d)"); | |||||
assertNull(parser.parse("")); | |||||
doTest("SG-1", parser, id(0, 3, "SG-1")); | |||||
doTest("SG-1 SG-2 SG-3", parser, id(0, 3, "SG-1"), id(5, 8, "SG-2"), id(10, 13, "SG-3")); | |||||
} | |||||
public void testSimple4() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("SG-(\\d)"); | |||||
assertNull(parser.parse("")); | |||||
doTest("SG-1", parser, id(3, 3, "1")); | |||||
doTest("SG-1 SG-2 SG-3", parser, id(3, 3, "1"), id(8, 8, "2"), id(13, 13, "3")); | |||||
} | |||||
public void testTwoLevel1() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("(SG-\\d)", "\\d"); | |||||
doTest("SG-1", parser, id(3, 3, "1")); | |||||
doTest("SG-1 SG-2 SG-3", parser, id(3, 3, "1"), id(8, 8, "2"), id(13, 13, "3")); | |||||
} | |||||
public void testTwoLevel2() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("xSG-\\dx", "\\d"); | |||||
doTest("SG-1 xSG-2x SG-3", parser, id(9, 9, "2")); | |||||
} | |||||
public void testTwoLevel3() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("[Ii]ssues?:?((\\s*(,|and)?\\s*#\\d+)+)", "\\d"); | |||||
doTest("Issues #3, #4 and #5: Git Bugtraq Configuration options (see #12)", parser, id(8, 8, "3"), id(12, 12, "4"), id(19, 19, "5")); | |||||
} | |||||
public void testThreeLevel() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("[ab]\\d[cd]", "a\\dc|b\\dd", "\\d"); | |||||
doTest("a1c a2d b3c b4d", parser, id(1, 1, "1"), id(13, 13, "4")); | |||||
} | |||||
public void testFogBugz() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("(?:Bug[zs]?\\s*IDs?\\s*|Cases?)[#:; ]+((\\d+[ ,:;#]*)+)", "\\d"); | |||||
doTest("Bug IDs: 3, 4, 5", parser, id(9, 9, "3"), id(12, 12, "4"), id(15, 15, "5")); | |||||
} | |||||
public void testFogBugzInvalid() throws BugtraqException { | |||||
final BugtraqParser parser = createParser("Bug[zs]?\\s*IDs?\\s*|Cases?[#:; ]+((\\d+[ ,:;#]*)+)", "\\d"); | |||||
doTest("Bug IDs: 3, 4, 5", parser); | |||||
} | |||||
// Utils ================================================================== | |||||
private BugtraqParser createParser(String ... regexs) throws BugtraqException { | |||||
return BugtraqParser.createInstance(Arrays.asList(regexs)); | |||||
} | |||||
private BugtraqParserIssueId id(int from, int to, String id) { | |||||
return new BugtraqParserIssueId(from, to, id); | |||||
} | |||||
private void doTest(String message, BugtraqParser parser, BugtraqParserIssueId... expectedIds) { | |||||
final List<BugtraqParserIssueId> actualIds = parser.parse(message); | |||||
assertEquals(expectedIds.length, actualIds.size()); | |||||
for (int index = 0; index < expectedIds.length; index++) { | |||||
final BugtraqParserIssueId expectedId = expectedIds[index]; | |||||
final BugtraqParserIssueId actualId = actualIds.get(index); | |||||
assertEquals(expectedId.getFrom(), actualId.getFrom()); | |||||
assertEquals(expectedId.getTo(), actualId.getTo()); | |||||
assertEquals(expectedId.getId(), actualId.getId()); | |||||
} | |||||
} | |||||
} |