{"action":"created","comment":{"url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/comments/38011760","id":38011760,"diff_hunk":"@@ -0,0 +1,180 @@\n+package com.isroot.stash.plugin;\n+\n+import java.util.*;\n+\n+import com.atlassian.soy.renderer.SoyException;\n+import com.atlassian.soy.renderer.SoyTemplateRenderer;\n+\n+import javax.servlet.http.HttpServlet;\n+import javax.servlet.http.HttpServletRequest;\n+import javax.servlet.http.HttpServletResponse;\n+\n+import com.google.common.collect.ImmutableMap;\n+\n+import javax.servlet.ServletException;\n+\n+import java.io.IOException;\n+\n+import com.atlassian.sal.api.pluginsettings.PluginSettings;\n+import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;\n+import com.atlassian.stash.setting.Settings;\n+import com.atlassian.stash.setting.SettingsValidationErrors;\n+\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import com.atlassian.stash.nav.NavBuilder;\n+\n+import com.atlassian.stash.hook.repository.RepositoryHookService;\n+\n+/**\n+ * @author Uldis Ansmits\n+ * @author Jim Bethancourt\n+ */\n+public class YaccConfigServlet extends HttpServlet {\n+\n+    private static final Logger log = LoggerFactory.getLogger(YaccConfigServlet.class);\n+    static final String SETTINGS_MAP = \"com.isroot.stash.plugin.yacc.settings\";\n+\n+    private final RepositoryHookService repositoryHookService;\n+    final private SoyTemplateRenderer soyTemplateRenderer;\n+    private final NavBuilder navBuilder;\n+    private ConfigValidator configValidator;\n+    private Map<String, String> fields;\n+    private Map<String, Iterable<String>> fieldErrors;\n+    private final PluginSettings pluginSettings;\n+    private HashMap<String, Object> settingsMap;\n+\n+    public YaccConfigServlet(SoyTemplateRenderer soyTemplateRenderer,\n+                             PluginSettingsFactory pluginSettingsFactory,\n+                             JiraService jiraService,\n+                             RepositoryHookService repositoryHookService,\n+                             NavBuilder navBuilder) {\n+        this.soyTemplateRenderer = soyTemplateRenderer;\n+        this.navBuilder = navBuilder;\n+        this.repositoryHookService = repositoryHookService;\n+\n+        pluginSettings = pluginSettingsFactory.createGlobalSettings();\n+\n+        configValidator = new ConfigValidator(jiraService);\n+\n+        fields = new HashMap<String, String>();\n+        fieldErrors = new HashMap<String, Iterable<String>>();\n+    }\n+\n+\n+    @SuppressWarnings(\"unchecked\")\n+    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {\n+        log.debug(\"doGet\");\n+        settingsMap = (HashMap<String, Object>) pluginSettings.get(SETTINGS_MAP);\n+        if (settingsMap == null) {\n+            settingsMap = new HashMap<String, Object>();\n+        }\n+\n+        validateSettings();\n+        doGetContinue(req, resp);\n+    }\n+\n+    public void validateSettings() {\n+        Settings settings = repositoryHookService.createSettingsBuilder()\n+                .addAll(settingsMap)\n+                .build();\n+        configValidator.validate(settings, new SettingsValidationErrorsImpl(fieldErrors), null);\n+    }\n+\n+    protected void doGetContinue(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {\n+        log.debug(\"doGetContinue\");\n+        fields.clear();\n+\n+        for (Map.Entry<String, Object> entry : settingsMap.entrySet()) {\n+            String key = entry.getKey();\n+            Object value = entry.getValue();\n+            log.debug(\"got plugin config \" + key + \"=\" + value + \" \" + value.getClass().getName());\n+            if (value instanceof String) {\n+                fields.put(key, (String) value);\n+            }\n+        }\n+\n+        log.debug(\"Config fields: \" + fields);\n+        log.debug(\"Field errors: \" + fieldErrors);\n+\n+        resp.setContentType(\"text/html;charset=UTF-8\");\n+        try {\n+            soyTemplateRenderer.render(resp.getWriter(), \"com.isroot.stash.plugin.yacc:yaccHook-config-serverside\", \"com.atlassian.stash.repository.hook.ref.config\",\n+                    ImmutableMap\n+                            .<String, Object>builder()\n+                            .put(\"config\", fields)\n+                            .put(\"errors\", fieldErrors)\n+                            .build()\n+            );\n+        } catch (SoyException e) {\n+            Throwable cause = e.getCause();\n+            if (cause instanceof IOException) {\n+                throw (IOException) cause;\n+            }\n+            throw new ServletException(e);\n+        }\n+\n+    }\n+\n+    public void addStringFieldValue(Map<String, Object> settingsMap, HttpServletRequest req, String fieldName) {\n+        String o;\n+        o = req.getParameter(fieldName);\n+        if (o != null && !o.isEmpty()) settingsMap.put(fieldName, o);\n+    }\n+\n+    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {\n+        settingsMap.clear();\n+\n+        for (Object key : req.getParameterMap().keySet()) {\n+            String parameterName = (String) key;\n+\n+            // Plugin settings persister only supports map of strings\n+            if (!parameterName.startsWith(\"errorMessage\") && !parameterName.equals(\"submit\")) {","path":"src/main/java/com/isroot/stash/plugin/YaccConfigServlet.java","position":133,"original_position":133,"commit_id":"f1bbb3584e1e0856b914e406a710e9be1b72bd97","original_commit_id":"f1bbb3584e1e0856b914e406a710e9be1b72bd97","user":{"login":"jimbethancourt","id":192431,"avatar_url":"https://avatars.githubusercontent.com/u/192431?v=3","gravatar_id":"","url":"https://api.github.com/users/jimbethancourt","html_url":"https://github.com/jimbethancourt","followers_url":"https://api.github.com/users/jimbethancourt/followers","following_url":"https://api.github.com/users/jimbethancourt/following{/other_user}","gists_url":"https://api.github.com/users/jimbethancourt/gists{/gist_id}","starred_url":"https://api.github.com/users/jimbethancourt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimbethancourt/subscriptions","organizations_url":"https://api.github.com/users/jimbethancourt/orgs","repos_url":"https://api.github.com/users/jimbethancourt/repos","events_url":"https://api.github.com/users/jimbethancourt/events{/privacy}","received_events_url":"https://api.github.com/users/jimbethancourt/received_events","type":"User","site_admin":false},"body":"Good news and bad news -- taking `!parameterName.startsWith(\"errorMessage\")` out, the header/footer settings and the other custom error messages were correctly saved and repopulated (in Stash 3.10.2).\r\n\r\nThe biggest concern I have is that the *Issue JQL Matcher* error message doesn't pop up an error message or redirect to a very useful error page -- it only shows a \"500 Error\" skull and crossbones page, at least for the local instance I have that doesn't have a JIRA application link set up.  It looks like this is a limitation of Stash itself looking at https://answers.atlassian.com/questions/229401/error-page-decorator-or-template-in-stash  The error message shows up in the Stash logs, but the 500 page doesn't indicate this...  How concerned are you about this?\r\n\r\nI will proceed with committing and pushing the Config servlet with `!parameterName.startsWith(\"errorMessage\")` removed.\r\n\r\nThanks,\r\nJim","created_at":"2015-08-26T17:44:33Z","updated_at":"2015-08-26T17:44:33Z","html_url":"https://github.com/sford/yet-another-commit-checker/pull/69#discussion_r38011760","pull_request_url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69","_links":{"self":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/comments/38011760"},"html":{"href":"https://github.com/sford/yet-another-commit-checker/pull/69#discussion_r38011760"},"pull_request":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69"}}},"pull_request":{"url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69","id":42742137,"html_url":"https://github.com/sford/yet-another-commit-checker/pull/69","diff_url":"https://github.com/sford/yet-another-commit-checker/pull/69.diff","patch_url":"https://github.com/sford/yet-another-commit-checker/pull/69.patch","issue_url":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/69","number":69,"state":"open","locked":false,"title":"Added global configuration","user":{"login":"jimbethancourt","id":192431,"avatar_url":"https://avatars.githubusercontent.com/u/192431?v=3","gravatar_id":"","url":"https://api.github.com/users/jimbethancourt","html_url":"https://github.com/jimbethancourt","followers_url":"https://api.github.com/users/jimbethancourt/followers","following_url":"https://api.github.com/users/jimbethancourt/following{/other_user}","gists_url":"https://api.github.com/users/jimbethancourt/gists{/gist_id}","starred_url":"https://api.github.com/users/jimbethancourt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimbethancourt/subscriptions","organizations_url":"https://api.github.com/users/jimbethancourt/orgs","repos_url":"https://api.github.com/users/jimbethancourt/repos","events_url":"https://api.github.com/users/jimbethancourt/events{/privacy}","received_events_url":"https://api.github.com/users/jimbethancourt/received_events","type":"User","site_admin":false},"body":"Added capability to have a global configuration that will provide a default configuration for all projects that do not have a repository-level configuration.  Repository configuration will override global configuration if present.","created_at":"2015-08-18T20:04:03Z","updated_at":"2015-08-26T17:44:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"28ce146c710a7e736c7db98771ceae04b21e9059","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69/commits","review_comments_url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69/comments","review_comment_url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/69/comments","statuses_url":"https://api.github.com/repos/sford/yet-another-commit-checker/statuses/f1bbb3584e1e0856b914e406a710e9be1b72bd97","head":{"label":"jimbethancourt:master","ref":"master","sha":"f1bbb3584e1e0856b914e406a710e9be1b72bd97","user":{"login":"jimbethancourt","id":192431,"avatar_url":"https://avatars.githubusercontent.com/u/192431?v=3","gravatar_id":"","url":"https://api.github.com/users/jimbethancourt","html_url":"https://github.com/jimbethancourt","followers_url":"https://api.github.com/users/jimbethancourt/followers","following_url":"https://api.github.com/users/jimbethancourt/following{/other_user}","gists_url":"https://api.github.com/users/jimbethancourt/gists{/gist_id}","starred_url":"https://api.github.com/users/jimbethancourt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimbethancourt/subscriptions","organizations_url":"https://api.github.com/users/jimbethancourt/orgs","repos_url":"https://api.github.com/users/jimbethancourt/repos","events_url":"https://api.github.com/users/jimbethancourt/events{/privacy}","received_events_url":"https://api.github.com/users/jimbethancourt/received_events","type":"User","site_admin":false},"repo":{"id":40623799,"name":"yet-another-commit-checker","full_name":"jimbethancourt/yet-another-commit-checker","owner":{"login":"jimbethancourt","id":192431,"avatar_url":"https://avatars.githubusercontent.com/u/192431?v=3","gravatar_id":"","url":"https://api.github.com/users/jimbethancourt","html_url":"https://github.com/jimbethancourt","followers_url":"https://api.github.com/users/jimbethancourt/followers","following_url":"https://api.github.com/users/jimbethancourt/following{/other_user}","gists_url":"https://api.github.com/users/jimbethancourt/gists{/gist_id}","starred_url":"https://api.github.com/users/jimbethancourt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimbethancourt/subscriptions","organizations_url":"https://api.github.com/users/jimbethancourt/orgs","repos_url":"https://api.github.com/users/jimbethancourt/repos","events_url":"https://api.github.com/users/jimbethancourt/events{/privacy}","received_events_url":"https://api.github.com/users/jimbethancourt/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jimbethancourt/yet-another-commit-checker","description":"An Atlassian Stash plugin to enforce commit message requirements.","fork":true,"url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker","forks_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/forks","keys_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/teams","hooks_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/hooks","issue_events_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/issues/events{/number}","events_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/events","assignees_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/assignees{/user}","branches_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/branches{/branch}","tags_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/tags","blobs_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/git/refs{/sha}","trees_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/statuses/{sha}","languages_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/languages","stargazers_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/stargazers","contributors_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/contributors","subscribers_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/subscribers","subscription_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/subscription","commits_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/commits{/sha}","git_commits_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/git/commits{/sha}","comments_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/comments{/number}","issue_comment_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/issues/comments{/number}","contents_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/contents/{+path}","compare_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/merges","archive_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/downloads","issues_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/issues{/number}","pulls_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/pulls{/number}","milestones_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/milestones{/number}","notifications_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/labels{/name}","releases_url":"https://api.github.com/repos/jimbethancourt/yet-another-commit-checker/releases{/id}","created_at":"2015-08-12T20:53:08Z","updated_at":"2015-08-12T20:53:08Z","pushed_at":"2015-08-18T19:59:42Z","git_url":"git://github.com/jimbethancourt/yet-another-commit-checker.git","ssh_url":"git@github.com:jimbethancourt/yet-another-commit-checker.git","clone_url":"https://github.com/jimbethancourt/yet-another-commit-checker.git","svn_url":"https://github.com/jimbethancourt/yet-another-commit-checker","homepage":null,"size":264,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"sford:master","ref":"master","sha":"ba50bf35f572f43e9863d3e3f9b8689b6548de07","user":{"login":"sford","id":1066452,"avatar_url":"https://avatars.githubusercontent.com/u/1066452?v=3","gravatar_id":"","url":"https://api.github.com/users/sford","html_url":"https://github.com/sford","followers_url":"https://api.github.com/users/sford/followers","following_url":"https://api.github.com/users/sford/following{/other_user}","gists_url":"https://api.github.com/users/sford/gists{/gist_id}","starred_url":"https://api.github.com/users/sford/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sford/subscriptions","organizations_url":"https://api.github.com/users/sford/orgs","repos_url":"https://api.github.com/users/sford/repos","events_url":"https://api.github.com/users/sford/events{/privacy}","received_events_url":"https://api.github.com/users/sford/received_events","type":"User","site_admin":false},"repo":{"id":15828823,"name":"yet-another-commit-checker","full_name":"sford/yet-another-commit-checker","owner":{"login":"sford","id":1066452,"avatar_url":"https://avatars.githubusercontent.com/u/1066452?v=3","gravatar_id":"","url":"https://api.github.com/users/sford","html_url":"https://github.com/sford","followers_url":"https://api.github.com/users/sford/followers","following_url":"https://api.github.com/users/sford/following{/other_user}","gists_url":"https://api.github.com/users/sford/gists{/gist_id}","starred_url":"https://api.github.com/users/sford/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sford/subscriptions","organizations_url":"https://api.github.com/users/sford/orgs","repos_url":"https://api.github.com/users/sford/repos","events_url":"https://api.github.com/users/sford/events{/privacy}","received_events_url":"https://api.github.com/users/sford/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sford/yet-another-commit-checker","description":"An Atlassian Stash plugin to enforce commit message requirements.","fork":false,"url":"https://api.github.com/repos/sford/yet-another-commit-checker","forks_url":"https://api.github.com/repos/sford/yet-another-commit-checker/forks","keys_url":"https://api.github.com/repos/sford/yet-another-commit-checker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sford/yet-another-commit-checker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sford/yet-another-commit-checker/teams","hooks_url":"https://api.github.com/repos/sford/yet-another-commit-checker/hooks","issue_events_url":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/events{/number}","events_url":"https://api.github.com/repos/sford/yet-another-commit-checker/events","assignees_url":"https://api.github.com/repos/sford/yet-another-commit-checker/assignees{/user}","branches_url":"https://api.github.com/repos/sford/yet-another-commit-checker/branches{/branch}","tags_url":"https://api.github.com/repos/sford/yet-another-commit-checker/tags","blobs_url":"https://api.github.com/repos/sford/yet-another-commit-checker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sford/yet-another-commit-checker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sford/yet-another-commit-checker/git/refs{/sha}","trees_url":"https://api.github.com/repos/sford/yet-another-commit-checker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sford/yet-another-commit-checker/statuses/{sha}","languages_url":"https://api.github.com/repos/sford/yet-another-commit-checker/languages","stargazers_url":"https://api.github.com/repos/sford/yet-another-commit-checker/stargazers","contributors_url":"https://api.github.com/repos/sford/yet-another-commit-checker/contributors","subscribers_url":"https://api.github.com/repos/sford/yet-another-commit-checker/subscribers","subscription_url":"https://api.github.com/repos/sford/yet-another-commit-checker/subscription","commits_url":"https://api.github.com/repos/sford/yet-another-commit-checker/commits{/sha}","git_commits_url":"https://api.github.com/repos/sford/yet-another-commit-checker/git/commits{/sha}","comments_url":"https://api.github.com/repos/sford/yet-another-commit-checker/comments{/number}","issue_comment_url":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/comments{/number}","contents_url":"https://api.github.com/repos/sford/yet-another-commit-checker/contents/{+path}","compare_url":"https://api.github.com/repos/sford/yet-another-commit-checker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sford/yet-another-commit-checker/merges","archive_url":"https://api.github.com/repos/sford/yet-another-commit-checker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sford/yet-another-commit-checker/downloads","issues_url":"https://api.github.com/repos/sford/yet-another-commit-checker/issues{/number}","pulls_url":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls{/number}","milestones_url":"https://api.github.com/repos/sford/yet-another-commit-checker/milestones{/number}","notifications_url":"https://api.github.com/repos/sford/yet-another-commit-checker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sford/yet-another-commit-checker/labels{/name}","releases_url":"https://api.github.com/repos/sford/yet-another-commit-checker/releases{/id}","created_at":"2014-01-11T19:13:06Z","updated_at":"2015-07-09T09:24:11Z","pushed_at":"2015-08-18T20:04:04Z","git_url":"git://github.com/sford/yet-another-commit-checker.git","ssh_url":"git@github.com:sford/yet-another-commit-checker.git","clone_url":"https://github.com/sford/yet-another-commit-checker.git","svn_url":"https://github.com/sford/yet-another-commit-checker","homepage":null,"size":757,"stargazers_count":26,"watchers_count":26,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":25,"mirror_url":null,"open_issues_count":20,"forks":25,"open_issues":20,"watchers":26,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69"},"html":{"href":"https://github.com/sford/yet-another-commit-checker/pull/69"},"issue":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/69"},"comments":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/issues/69/comments"},"review_comments":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69/comments"},"review_comment":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/pulls/69/commits"},"statuses":{"href":"https://api.github.com/repos/sford/yet-another-commit-checker/statuses/f1bbb3584e1e0856b914e406a710e9be1b72bd97"}}}}