Add support for per-repository bugtraq configuration
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: Iaba305bf4280d08cc4d1abf533c2f1365470a43f
10 files added
10 files modified
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <classpath> |
| | | <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/bugtraq" output="bin/test-classes" /> |
| | | <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/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/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/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" /> |
New file |
| | |
| | | [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. |
| | | sourceDirectories: |
| | | - compile 'src/main/java' |
| | | - compile 'src/main/bugtraq' |
| | | - compile 'src/main/dagger' apt |
| | | - test 'src/test/java' |
| | | - test 'src/test/bugtraq' |
| | | # Moxie supports one site-scoped directory for mx:doc |
| | | - site 'src/site' |
| | | |
| | |
| | | - compile 'com.squareup.dagger:dagger:1.1.0' :war apt |
| | | - compile 'com.squareup.dagger:dagger-compiler:1.1.0' :war optional apt |
| | | # Standard dependencies |
| | | - compile 'com.intellij:annotations:12.0' :war |
| | | - compile 'com.beust:jcommander:1.17' :fedclient :authority |
| | | - compile 'log4j:log4j:1.2.17' :war :fedclient :authority |
| | | - compile 'org.slf4j:slf4j-api:1.6.6' :war :fedclient :authority |
| | |
| | | <exclude-output /> |
| | | <content url="file://$MODULE_DIR$"> |
| | | <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/test/java" isTestSource="true" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/test/bugtraq" isTestSource="true" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" /> |
| | | </content> |
| | | <orderEntry type="sourceFolder" forTests="false" /> |
| | |
| | | </library> |
| | | </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"> |
| | | <library name="jcommander-1.17.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/jcommander-1.17.jar!/" /> |
| | |
| | | - 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 |
| | | - Automatically display common repository root documents as tabs on the docs page |
| | | - Support bugtraq configuration in collaboration with syntevo |
| | | dependencyChanges: |
| | | - updated to Jetty 8.1.13 |
| | | - updated to JGit 3.1.0 |
| | |
| | | - fpeters.fae |
| | | - David Ostrovsky |
| | | - Alex Lewis |
| | | - Marc Strapetz |
| | | } |
| | | |
| | | # |
New file |
| | |
| | | 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. |
New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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());
|
| | | entry.published = commit.getCommitterIdent().getWhen();
|
| | | entry.contentType = "text/html";
|
| | | String message = processor.processCommitMessage(model, commit.getFullMessage());
|
| | | String message = processor.processCommitMessage(repository, model, commit.getFullMessage());
|
| | | entry.content = message;
|
| | | entry.repository = model.name;
|
| | | entry.branch = objectId;
|
| | |
| | | */ |
| | | package com.gitblit.utils; |
| | | |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | | |
| | | import org.eclipse.jgit.errors.ConfigInvalidException; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.syntevo.bugtraq.BugtraqConfig; |
| | | import com.syntevo.bugtraq.BugtraqFormatter; |
| | | import com.syntevo.bugtraq.BugtraqFormatter.OutputHandler; |
| | | |
| | | public class MessageProcessor { |
| | | |
| | |
| | | * This method uses the preferred renderer to transform the commit message. |
| | | * |
| | | * @param repository |
| | | * @param model |
| | | * @param text |
| | | * @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: |
| | | try { |
| | | String prepared = processCommitMessageRegex(repository.name, text); |
| | | String prepared = processCommitMessageRegex(repository, model.name, text); |
| | | return MarkdownUtils.transformMarkdown(prepared); |
| | | } catch (Exception e) { |
| | | logger.error("Failed to render commit message as markdown", e); |
| | |
| | | break; |
| | | } |
| | | |
| | | return processPlainCommitMessage(repository.name, text); |
| | | return processPlainCommitMessage(repository, model.name, text); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * This method assumes the commit message is plain text. |
| | | * |
| | | * @param repository |
| | | * @param repositoryName |
| | | * @param text |
| | | * @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); |
| | | html = processCommitMessageRegex(repositoryName, html); |
| | | html = processCommitMessageRegex(repository, repositoryName, html); |
| | | return StringUtils.breakLinesForHtml(html); |
| | | |
| | | } |
| | |
| | | * Apply globally or per-repository specified regex substitutions to the |
| | | * commit message. |
| | | * |
| | | * @param repository |
| | | * @param repositoryName |
| | | * @param text |
| | | * @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>(); |
| | | // global regex keys |
| | | if (settings.getBoolean(Keys.regex.global, false)) { |
| | |
| | | + 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; |
| | | } |
| | | |
| | | 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(WicketUtils.createTimestampLabel("authorDate", entry.notesRef |
| | | .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)); |
| | | } |
| | | }; |
| | |
| | | item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent()));
|
| | | item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef
|
| | | .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));
|
| | | }
|
| | | };
|
| | |
| | | .newPathParameter(repositoryName, entry.commitId, path)));
|
| | | }
|
| | |
|
| | | |
| | |
|
| | | // quick links
|
| | | if (entry.isSubmodule()) {
|
| | | item.add(new ExternalLink("raw", "").setEnabled(false));
|
| | | |
| | |
|
| | | // submodule
|
| | | item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils
|
| | | .newPathParameter(repositoryName, entry.commitId, entry.path))
|
| | |
| | |
|
| | | protected void addFullText(String wicketId, String text) {
|
| | | RepositoryModel model = getRepositoryModel();
|
| | | String content = messageProcessor().processCommitMessage(model, text);
|
| | | String content = messageProcessor().processCommitMessage(r, model, text);
|
| | | String html;
|
| | | switch (model.commitMessageRenderer) {
|
| | | case MARKDOWN:
|
| | |
| | | vertical-align: text-bottom;
|
| | | }
|
| | |
|
| | | a.bugtraq {
|
| | | font-weight: bold;
|
| | | }
|
| | |
|
| | | [class^="icon-"], [class*=" icon-"] i {
|
| | | /* override for a links that look like bootstrap buttons */
|
| | | vertical-align: text-bottom;
|
New file |
| | |
| | | /* |
| | | * 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); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * 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()); |
| | | } |
| | | } |
| | | } |