{"action":"created","comment":{"url":"https://api.github.com/repos/apache/bookkeeper/pulls/comments/239999987","pull_request_review_id":182939230,"id":239999987,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzOTk5OTk4Nw==","diff_hunk":"@@ -0,0 +1,325 @@\n+/*\n+ * Licensed to the Apache Software Foundation (ASF) under one\n+ * or more contributor license agreements.  See the NOTICE file\n+ * distributed with this work for additional information\n+ * regarding copyright ownership.  The ASF licenses this file\n+ * to you under the Apache License, Version 2.0 (the\n+ * \"License\"); you may not use this file except in compliance\n+ * with the License.  You may obtain a copy of the License at\n+ *\n+ *   http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing,\n+ * software distributed under the License is distributed on an\n+ * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n+ * KIND, either express or implied.  See the License for the\n+ * specific language governing permissions and limitations\n+ * under the License.\n+ */\n+\n+package org.apache.bookkeeper.common.conf;\n+\n+import static com.google.common.base.Preconditions.checkArgument;\n+\n+import com.google.common.collect.Sets;\n+import java.io.IOException;\n+import java.io.OutputStream;\n+import java.io.PrintStream;\n+import java.lang.reflect.Field;\n+import java.lang.reflect.Modifier;\n+import java.nio.file.Files;\n+import java.nio.file.Path;\n+import java.nio.file.StandardOpenOption;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.TreeSet;\n+import java.util.stream.Collectors;\n+import java.util.stream.IntStream;\n+import lombok.Getter;\n+import lombok.extern.slf4j.Slf4j;\n+import org.apache.commons.configuration.Configuration;\n+import org.apache.commons.lang.StringUtils;\n+\n+/**\n+ * A definition of a configuration instance.\n+ */\n+@Slf4j\n+@Getter\n+public class ConfigDef {\n+\n+    /**\n+     * Builder to build a configuration definition.\n+     */\n+    public static class Builder {\n+\n+        private final Set<ConfigKeyGroup> groups = new TreeSet<>(ConfigKeyGroup.ORDERING);\n+        private final Map<String, Set<ConfigKey>> settings = new HashMap<>();\n+\n+        private Builder() {}\n+\n+        /**\n+         * Add the config key group to the builder.\n+         *\n+         * @param group config key group\n+         * @return builder to build this configuration def\n+         */\n+        public Builder withConfigKeyGroup(ConfigKeyGroup group) {\n+            groups.add(group);\n+            return this;\n+        }\n+\n+        /**\n+         * Add the config key to the builder.\n+         *\n+         * @param key the key to add to the builder.\n+         * @return builder to build this configuration def\n+         */\n+        public Builder withConfigKey(ConfigKey key) {\n+            ConfigKeyGroup group = key.group();\n+            Set<ConfigKey> keys;\n+            String groupName;\n+            if (null == group) {\n+                groupName = \"\";\n+            } else {\n+                groupName = group.name();\n+                groups.add(group);\n+            }\n+            keys = settings.computeIfAbsent(groupName, name -> new TreeSet<>(ConfigKey.ORDERING));\n+            keys.add(key);\n+            return this;\n+        }\n+\n+        public ConfigDef build() {\n+            checkArgument(\n+                Sets.difference(\n+                    groups.stream().map(group -> group.name()).collect(Collectors.toSet()),\n+                    settings.keySet()\n+                ).isEmpty(),\n+                \"Configuration Key Groups doesn't match with keys\");\n+            return new ConfigDef(groups, settings);\n+        }\n+\n+    }\n+\n+    /**\n+     * Create a builder to build a config def.\n+     *\n+     * @return builder to build a config def.\n+     */\n+    public static Builder builder() {\n+        return new Builder();\n+    }\n+\n+    private final Set<ConfigKeyGroup> groups;\n+    private final Map<String, Set<ConfigKey>> settings;\n+    private final Map<String, ConfigKey> keys;\n+\n+    private ConfigDef(Set<ConfigKeyGroup> groups,\n+                      Map<String, Set<ConfigKey>> settings) {\n+        this.groups = groups;\n+        this.settings = settings;\n+        this.keys = settings.values()\n+            .stream()\n+            .flatMap(keys -> keys.stream())\n+            .collect(Collectors.toSet())\n+            .stream()\n+            .collect(Collectors.toMap(\n+                key -> key.name(),\n+                key -> key\n+            ));\n+    }\n+\n+    /**\n+     * Validate if the provided <tt>conf</tt> is a valid configuration of this configuration definition.\n+     *\n+     * @param conf the configuration to validate\n+     */\n+    public void validate(Configuration conf) throws ConfigException {\n+        for (ConfigKey key : keys.values()) {\n+            key.validate(conf);\n+        }\n+    }\n+\n+    /**\n+     * Build the config definitation of a config class.\n+     *\n+     * @param configClass config class\n+     * @return config definition.\n+     */\n+    @SuppressWarnings(\"unchecked\")\n+    public static ConfigDef of(Class configClass) {\n+        ConfigDef.Builder builder = ConfigDef.builder();\n+\n+        Field[] fields = configClass.getDeclaredFields();\n+        for (Field field : fields) {\n+            if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(ConfigKey.class)) {\n+                field.setAccessible(true);\n+                try {\n+                    builder.withConfigKey((ConfigKey) field.get(null));\n+                } catch (IllegalAccessException e) {\n+                    log.error(\"Illegal to access {}#{}\", configClass.getSimpleName(), field.getName(), e);\n+                }\n+            }\n+        }\n+\n+        return builder.build();\n+    }\n+\n+    //\n+    // Methods to save the configuration to an {@link OutputStream}\n+    //\n+\n+    private static final int MAX_COLUMN_SIZE = 80;\n+    private static final String COMMENT_PREFIX = \"# \";\n+\n+    public void save(Path path) throws IOException  {\n+        try (OutputStream stream = Files.newOutputStream(\n+            path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {\n+            save(stream);\n+        }\n+    }\n+\n+    public void save(OutputStream os) {\n+        try (PrintStream ps = new PrintStream(os)) {","path":"bookkeeper-common/src/main/java/org/apache/bookkeeper/common/conf/ConfigDef.java","position":185,"original_position":185,"commit_id":"8244047dc1b7d9b571a7412858b408e1d7cab0ef","original_commit_id":"8244047dc1b7d9b571a7412858b408e1d7cab0ef","user":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"body":"EOL should be already handled. what is your concern here? ","created_at":"2018-12-08T09:57:53Z","updated_at":"2018-12-08T09:57:53Z","html_url":"https://github.com/apache/bookkeeper/pull/1869#discussion_r239999987","pull_request_url":"https://api.github.com/repos/apache/bookkeeper/pulls/1869","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/comments/239999987"},"html":{"href":"https://github.com/apache/bookkeeper/pull/1869#discussion_r239999987"},"pull_request":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/1869"}},"in_reply_to_id":239999861},"pull_request":{"url":"https://api.github.com/repos/apache/bookkeeper/pulls/1869","id":237057712,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM3MDU3NzEy","html_url":"https://github.com/apache/bookkeeper/pull/1869","diff_url":"https://github.com/apache/bookkeeper/pull/1869.diff","patch_url":"https://github.com/apache/bookkeeper/pull/1869.patch","issue_url":"https://api.github.com/repos/apache/bookkeeper/issues/1869","number":1869,"state":"open","locked":false,"title":"Introduce a configuration framework for better organizing and documentating configuration settings","user":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"body":"Descriptions of the changes in this PR:\r\n\r\n### Motivation\r\n\r\nOne common task in developing bookkeeper is to make sure all the configuration\r\nsettings are well documented, and the configuration file we ship in each release\r\nis in-sync with the code itself.\r\n\r\nHowever maintaining things in-sync is non-trivial. This proposal is exploring\r\na new way to manage configuration settings for better documentation.\r\n\r\n### Changes\r\n\r\n- Introduce `ConfigKey` for defining a configuration setting key in a configuration\r\n- Introduce `ConfigKeyGroup` for grouping configuration settings together\r\n- Introduce `ConfigDef` for generating the configuration definition for a given configuration\r\n- Add a `save` method for saving a configuration definition into a configuration file\r\n\r\nMaster Issue: #1867 \r\n\r\n> ---\r\n> In order to uphold a high standard for quality for code contributions, Apache BookKeeper runs various precommit\r\n> checks for pull requests. A pull request can only be merged when it passes precommit checks. However running all\r\n> the precommit checks can take a long time, some trivial changes don't need to run all the precommit checks. You\r\n> can check following list to skip the tests that don't need to run for your pull request. Leave them unchecked if\r\n> you are not sure, committers will help you:\r\n>\r\n> - [ ] [skip bookkeeper-server bookie tests]: skip testing `org.apache.bookkeeper.bookie` in bookkeeper-server module.\r\n> - [ ] [skip bookkeeper-server client tests]: skip testing `org.apache.bookkeeper.client` in bookkeeper-server module.\r\n> - [ ] [skip bookkeeper-server replication tests]: skip testing `org.apache.bookkeeper.replication` in bookkeeper-server module.\r\n> - [ ] [skip bookkeeper-server tls tests]: skip testing `org.apache.bookkeeper.tls` in bookkeeper-server module.\r\n> - [ ] [skip bookkeeper-server remaining tests]: skip testing all other tests in bookkeeper-server module.\r\n> - [ ] [skip integration tests]: skip docker based integration tests. if you make java code changes, you shouldn't skip integration tests.\r\n> - [ ] [skip build java8]: skip build on java8. *ONLY* skip this when *ONLY* changing files under documentation under `site`.\r\n> - [ ] [skip build java9]: skip build on java9. *ONLY* skip this when *ONLY* changing files under documentation under `site`.\r\n> ---\r\n\r\n> ---\r\n> Be sure to do all of the following to help us incorporate your contribution\r\n> quickly and easily:\r\n>\r\n> If this PR is a BookKeeper Proposal (BP):\r\n>\r\n> - [ ] Make sure the PR title is formatted like:\r\n>     `<BP-#>: Description of bookkeeper proposal`\r\n>     `e.g. BP-1: 64 bits ledger is support`\r\n> - [ ] Attach the master issue link in the description of this PR.\r\n> - [ ] Attach the google doc link if the BP is written in Google Doc.\r\n>\r\n> Otherwise:\r\n> \r\n> - [ ] Make sure the PR title is formatted like:\r\n>     `<Issue #>: Description of pull request`\r\n>     `e.g. Issue 123: Description ...`\r\n> - [ ] Make sure tests pass via `mvn clean apache-rat:check install spotbugs:check`.\r\n> - [ ] Replace `<Issue #>` in the title with the actual Issue number.\r\n> \r\n> ---\r\n","created_at":"2018-12-08T09:32:10Z","updated_at":"2018-12-08T09:57:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"136f820c2bc1d9febb14cfde07eb339bf7663e00","assignee":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"assignees":[{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1064128474,"node_id":"MDU6TGFiZWwxMDY0MTI4NDc0","url":"https://api.github.com/repos/apache/bookkeeper/labels/area/config","name":"area/config","color":"f9d0c4","default":false},{"id":636302215,"node_id":"MDU6TGFiZWw2MzYzMDIyMTU=","url":"https://api.github.com/repos/apache/bookkeeper/labels/area/documentation","name":"area/documentation","color":"f9d0c4","default":false},{"id":769552700,"node_id":"MDU6TGFiZWw3Njk1NTI3MDA=","url":"https://api.github.com/repos/apache/bookkeeper/labels/type/improvement","name":"type/improvement","color":"fbca04","default":false}],"milestone":{"url":"https://api.github.com/repos/apache/bookkeeper/milestones/5","html_url":"https://github.com/apache/bookkeeper/milestone/5","labels_url":"https://api.github.com/repos/apache/bookkeeper/milestones/5/labels","id":3566485,"node_id":"MDk6TWlsZXN0b25lMzU2NjQ4NQ==","number":5,"title":"4.9.0","description":"Release 4.9.0","creator":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"open_issues":42,"closed_issues":184,"state":"open","created_at":"2018-08-13T18:10:09Z","updated_at":"2018-12-08T09:32:10Z","due_on":"2018-11-15T08:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/apache/bookkeeper/pulls/1869/commits","review_comments_url":"https://api.github.com/repos/apache/bookkeeper/pulls/1869/comments","review_comment_url":"https://api.github.com/repos/apache/bookkeeper/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/bookkeeper/issues/1869/comments","statuses_url":"https://api.github.com/repos/apache/bookkeeper/statuses/8244047dc1b7d9b571a7412858b408e1d7cab0ef","head":{"label":"sijie:config_defs","ref":"config_defs","sha":"8244047dc1b7d9b571a7412858b408e1d7cab0ef","user":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"repo":{"id":3747333,"node_id":"MDEwOlJlcG9zaXRvcnkzNzQ3MzMz","name":"bookkeeper","full_name":"sijie/bookkeeper","private":false,"owner":{"login":"sijie","id":1217863,"node_id":"MDQ6VXNlcjEyMTc4NjM=","avatar_url":"https://avatars2.githubusercontent.com/u/1217863?v=4","gravatar_id":"","url":"https://api.github.com/users/sijie","html_url":"https://github.com/sijie","followers_url":"https://api.github.com/users/sijie/followers","following_url":"https://api.github.com/users/sijie/following{/other_user}","gists_url":"https://api.github.com/users/sijie/gists{/gist_id}","starred_url":"https://api.github.com/users/sijie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sijie/subscriptions","organizations_url":"https://api.github.com/users/sijie/orgs","repos_url":"https://api.github.com/users/sijie/repos","events_url":"https://api.github.com/users/sijie/events{/privacy}","received_events_url":"https://api.github.com/users/sijie/received_events","type":"User","site_admin":false},"html_url":"https://github.com/sijie/bookkeeper","description":"Mirror of Apache Bookkeeper","fork":true,"url":"https://api.github.com/repos/sijie/bookkeeper","forks_url":"https://api.github.com/repos/sijie/bookkeeper/forks","keys_url":"https://api.github.com/repos/sijie/bookkeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sijie/bookkeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sijie/bookkeeper/teams","hooks_url":"https://api.github.com/repos/sijie/bookkeeper/hooks","issue_events_url":"https://api.github.com/repos/sijie/bookkeeper/issues/events{/number}","events_url":"https://api.github.com/repos/sijie/bookkeeper/events","assignees_url":"https://api.github.com/repos/sijie/bookkeeper/assignees{/user}","branches_url":"https://api.github.com/repos/sijie/bookkeeper/branches{/branch}","tags_url":"https://api.github.com/repos/sijie/bookkeeper/tags","blobs_url":"https://api.github.com/repos/sijie/bookkeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sijie/bookkeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sijie/bookkeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/sijie/bookkeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sijie/bookkeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/sijie/bookkeeper/languages","stargazers_url":"https://api.github.com/repos/sijie/bookkeeper/stargazers","contributors_url":"https://api.github.com/repos/sijie/bookkeeper/contributors","subscribers_url":"https://api.github.com/repos/sijie/bookkeeper/subscribers","subscription_url":"https://api.github.com/repos/sijie/bookkeeper/subscription","commits_url":"https://api.github.com/repos/sijie/bookkeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/sijie/bookkeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/sijie/bookkeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/sijie/bookkeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/sijie/bookkeeper/contents/{+path}","compare_url":"https://api.github.com/repos/sijie/bookkeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sijie/bookkeeper/merges","archive_url":"https://api.github.com/repos/sijie/bookkeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sijie/bookkeeper/downloads","issues_url":"https://api.github.com/repos/sijie/bookkeeper/issues{/number}","pulls_url":"https://api.github.com/repos/sijie/bookkeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/sijie/bookkeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/sijie/bookkeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sijie/bookkeeper/labels{/name}","releases_url":"https://api.github.com/repos/sijie/bookkeeper/releases{/id}","deployments_url":"https://api.github.com/repos/sijie/bookkeeper/deployments","created_at":"2012-03-17T11:57:47Z","updated_at":"2018-12-04T02:02:02Z","pushed_at":"2018-12-08T09:25:34Z","git_url":"git://github.com/sijie/bookkeeper.git","ssh_url":"git@github.com:sijie/bookkeeper.git","clone_url":"https://github.com/sijie/bookkeeper.git","svn_url":"https://github.com/sijie/bookkeeper","homepage":null,"size":23016,"stargazers_count":4,"watchers_count":4,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":2,"open_issues":0,"watchers":4,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"dd684b30c734642dc1347cd931cb483de2ef4888","user":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":1575956,"node_id":"MDEwOlJlcG9zaXRvcnkxNTc1OTU2","name":"bookkeeper","full_name":"apache/bookkeeper","private":false,"owner":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/apache/bookkeeper","description":"Apache Bookkeeper","fork":false,"url":"https://api.github.com/repos/apache/bookkeeper","forks_url":"https://api.github.com/repos/apache/bookkeeper/forks","keys_url":"https://api.github.com/repos/apache/bookkeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/bookkeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/bookkeeper/teams","hooks_url":"https://api.github.com/repos/apache/bookkeeper/hooks","issue_events_url":"https://api.github.com/repos/apache/bookkeeper/issues/events{/number}","events_url":"https://api.github.com/repos/apache/bookkeeper/events","assignees_url":"https://api.github.com/repos/apache/bookkeeper/assignees{/user}","branches_url":"https://api.github.com/repos/apache/bookkeeper/branches{/branch}","tags_url":"https://api.github.com/repos/apache/bookkeeper/tags","blobs_url":"https://api.github.com/repos/apache/bookkeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/bookkeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/bookkeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/bookkeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/bookkeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/bookkeeper/languages","stargazers_url":"https://api.github.com/repos/apache/bookkeeper/stargazers","contributors_url":"https://api.github.com/repos/apache/bookkeeper/contributors","subscribers_url":"https://api.github.com/repos/apache/bookkeeper/subscribers","subscription_url":"https://api.github.com/repos/apache/bookkeeper/subscription","commits_url":"https://api.github.com/repos/apache/bookkeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/bookkeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/bookkeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/bookkeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/bookkeeper/contents/{+path}","compare_url":"https://api.github.com/repos/apache/bookkeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/bookkeeper/merges","archive_url":"https://api.github.com/repos/apache/bookkeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/bookkeeper/downloads","issues_url":"https://api.github.com/repos/apache/bookkeeper/issues{/number}","pulls_url":"https://api.github.com/repos/apache/bookkeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/bookkeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/bookkeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/bookkeeper/labels{/name}","releases_url":"https://api.github.com/repos/apache/bookkeeper/releases{/id}","deployments_url":"https://api.github.com/repos/apache/bookkeeper/deployments","created_at":"2011-04-06T07:00:07Z","updated_at":"2018-12-08T09:46:14Z","pushed_at":"2018-12-08T09:32:10Z","git_url":"git://github.com/apache/bookkeeper.git","ssh_url":"git@github.com:apache/bookkeeper.git","clone_url":"https://github.com/apache/bookkeeper.git","svn_url":"https://github.com/apache/bookkeeper","homepage":"https://bookkeeper.apache.org","size":39480,"stargazers_count":518,"watchers_count":518,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":213,"mirror_url":null,"archived":false,"open_issues_count":182,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":213,"open_issues":182,"watchers":518,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/1869"},"html":{"href":"https://github.com/apache/bookkeeper/pull/1869"},"issue":{"href":"https://api.github.com/repos/apache/bookkeeper/issues/1869"},"comments":{"href":"https://api.github.com/repos/apache/bookkeeper/issues/1869/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/1869/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/bookkeeper/pulls/1869/commits"},"statuses":{"href":"https://api.github.com/repos/apache/bookkeeper/statuses/8244047dc1b7d9b571a7412858b408e1d7cab0ef"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"sijie"}}