You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2025/05/11 20:08:46 UTC

(maven-changes-plugin) branch master updated: Escape JIRA reserved words in JqlQueryBuilder (#127)

This is an automated email from the ASF dual-hosted git repository.

sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-changes-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 72781ef  Escape JIRA reserved words in JqlQueryBuilder (#127)
72781ef is described below

commit 72781ef87f6c89b8419a1b0f5e9a2252b7191d56
Author: Gary Gregory <ga...@users.noreply.github.com>
AuthorDate: Sun May 11 16:08:41 2025 -0400

    Escape JIRA reserved words in JqlQueryBuilder (#127)
---
 .../plugins/changes/jira/JqlQueryBuilder.java      | 198 ++++++++++++++++++++-
 .../changes/jira/JqlQueryBuilderTestCase.java      |  11 ++
 2 files changed, 208 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilder.java b/src/main/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilder.java
index 1676444..4963099 100644
--- a/src/main/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilder.java
+++ b/src/main/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilder.java
@@ -20,9 +20,11 @@ package org.apache.maven.plugins.changes.jira;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.commons.lang3.ArraySorter;
 import org.apache.maven.plugin.logging.Log;
 
 /**
@@ -33,6 +35,190 @@ import org.apache.maven.plugin.logging.Log;
  * @since 2.8
  */
 public class JqlQueryBuilder {
+
+    /**
+     * JQL <a href="https://confluence.atlassian.com/gsgtest/advanced-searching-815566220.html">reserved words</a>.
+     */
+    private static final String[] RESERVED_JQL_WORDS = ArraySorter.sort(new String[] {
+        "abort",
+        "access",
+        "add",
+        "after",
+        "alias",
+        "all",
+        "alter",
+        "and",
+        "any",
+        "as",
+        "asc",
+        "audit",
+        "avg",
+        "before",
+        "begin",
+        "between",
+        "boolean",
+        "break",
+        "by",
+        "byte",
+        "catch",
+        "cf",
+        "char",
+        "character",
+        "check",
+        "checkpoint",
+        "collate",
+        "collation",
+        "column",
+        "commit",
+        "connect",
+        "continue",
+        "count",
+        "create",
+        "current",
+        "date",
+        "decimal",
+        "declare",
+        "decrement",
+        "default",
+        "defaults",
+        "define",
+        "delete",
+        "delimiter",
+        "desc",
+        "difference",
+        "distinct",
+        "divide",
+        "do",
+        "double",
+        "drop",
+        "else",
+        "empty",
+        "encoding",
+        "end",
+        "equals",
+        "escape",
+        "exclusive",
+        "exec",
+        "execute",
+        "exists",
+        "explain",
+        "false",
+        "fetch",
+        "file",
+        "field",
+        "first",
+        "float",
+        "for",
+        "from",
+        "function",
+        "go",
+        "goto",
+        "grant",
+        "greater",
+        "group",
+        "having",
+        "identified",
+        "if",
+        "immediate",
+        "in",
+        "increment",
+        "index",
+        "initial",
+        "inner",
+        "inout",
+        "input",
+        "insert",
+        "int",
+        "integer",
+        "intersect",
+        "intersection",
+        "into",
+        "is",
+        "isempty",
+        "isnull",
+        "join",
+        "last",
+        "left",
+        "less",
+        "like",
+        "limit",
+        "lock",
+        "long",
+        "max",
+        "min",
+        "minus",
+        "mode",
+        "modify",
+        "modulo",
+        "more",
+        "multiply",
+        "next",
+        "noaudit",
+        "not",
+        "notin",
+        "nowait",
+        "null",
+        "number",
+        "object",
+        "of",
+        "on",
+        "option",
+        "or",
+        "order",
+        "outer",
+        "output",
+        "power",
+        "previous",
+        "prior",
+        "privileges",
+        "public",
+        "raise",
+        "raw",
+        "remainder",
+        "rename",
+        "resource",
+        "return",
+        "returns",
+        "revoke",
+        "right",
+        "row",
+        "rowid",
+        "rownum",
+        "rows",
+        "select",
+        "session",
+        "set",
+        "share",
+        "size",
+        "sqrt",
+        "start",
+        "strict",
+        "string",
+        "subtract",
+        "sum",
+        "synonym",
+        "table",
+        "then",
+        "to",
+        "trans",
+        "transaction",
+        "trigger",
+        "true",
+        "uid",
+        "union",
+        "unique",
+        "update",
+        "user",
+        "validate",
+        "values",
+        "view",
+        "when",
+        "whenever",
+        "where",
+        "while",
+        "with"
+    });
+
     private String filter = "";
 
     private boolean urlEncode = true;
@@ -265,10 +451,20 @@ public class JqlQueryBuilder {
 
     private void trimAndQuoteValue(String value) {
         String trimmedValue = value.trim();
-        if (trimmedValue.contains(" ") || trimmedValue.contains(".")) {
+        if (trimmedValue.contains(" ") || trimmedValue.contains(".") || isReservedJqlWord(trimmedValue)) {
             query.append("\"").append(trimmedValue).append("\"");
         } else {
             query.append(trimmedValue);
         }
     }
+
+    /**
+     * JQL <a href="https://confluence.atlassian.com/gsgtest/advanced-searching-815566220.html">reserved words</a>.
+     *
+     * @param value a string
+     * @return whether the given string is a JQL reserved word.
+     */
+    private boolean isReservedJqlWord(String value) {
+        return Arrays.binarySearch(RESERVED_JQL_WORDS, value.toLowerCase(Locale.ROOT)) > 0;
+    }
 }
diff --git a/src/test/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilderTestCase.java b/src/test/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilderTestCase.java
index 64959c0..83f854c 100644
--- a/src/test/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilderTestCase.java
+++ b/src/test/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilderTestCase.java
@@ -146,6 +146,17 @@ public class JqlQueryBuilderTestCase extends TestCase {
         assertEquals(expected, actual);
     }
 
+    public void testQuoteReservedWord() throws UnsupportedEncodingException {
+        String expected =
+                URLEncoder.encode("project = \"EXEC\" ORDER BY key ASC, assignee DESC, reporter ASC", ENCODING);
+
+        String actual = createBuilder()
+                .sortColumnNames("key ASC,assignee DESC, reporter ASC")
+                .project("EXEC")
+                .build();
+        assertEquals(expected, actual);
+    }
+
     private JqlQueryBuilder createBuilder() {
         return new JqlQueryBuilder(new SilentLog());
     }