{"action":"created","comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/comments/208299933","pull_request_review_id":144080684,"id":208299933,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwODI5OTkzMw==","diff_hunk":"@@ -0,0 +1,297 @@\n+# Copyright 2018 Google LLC\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+#     https://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+\n+require \"google/cloud/firestore/v1beta1\"\n+require \"google/cloud/firestore/convert\"\n+require \"google/cloud/firestore/watch/enumerator_queue\"\n+require \"google/cloud/firestore/watch/inventory\"\n+require \"monitor\"\n+require \"thread\"\n+\n+module Google\n+  module Cloud\n+    module Firestore\n+      ##\n+      # @private\n+      module Watch\n+        ##\n+        # @private\n+        class Listener\n+          include MonitorMixin\n+\n+          def self.for_doc_ref doc_ref, &callback\n+            raise ArgumentError if doc_ref.nil?\n+            raise ArgumentError if callback.nil?\n+\n+            init_listen_req = Google::Firestore::V1beta1::ListenRequest.new(\n+              database: doc_ref.client.path,\n+              add_target: Google::Firestore::V1beta1::Target.new(\n+                documents: \\\n+                  Google::Firestore::V1beta1::Target::DocumentsTarget.new(\n+                    documents: [doc_ref.path]\n+                  )\n+              )\n+            )\n+\n+            new nil, doc_ref, doc_ref.client, init_listen_req, &callback\n+          end\n+\n+          def self.for_query query, &callback\n+            raise ArgumentError if query.nil?\n+            raise ArgumentError if callback.nil?\n+\n+            init_listen_req = Google::Firestore::V1beta1::ListenRequest.new(\n+              database: query.client.path,\n+              add_target: Google::Firestore::V1beta1::Target.new(\n+                query: Google::Firestore::V1beta1::Target::QueryTarget.new(\n+                  parent: query.parent_path,\n+                  structured_query: query.query\n+                )\n+              )\n+            )\n+\n+            new query, nil, query.client, init_listen_req, &callback\n+          end\n+\n+          def initialize query, doc_ref, client, init_listen_req, &callback\n+            @query = query\n+            @doc_ref = doc_ref\n+            @client = client\n+            @init_listen_req = init_listen_req\n+            @callback = callback\n+\n+            super() # to init MonitorMixin\n+          end\n+\n+          def start\n+            synchronize { start_listening! }\n+            self\n+          end\n+\n+          def stop\n+            synchronize do\n+              @stopped = true\n+              @request_queue.push self if @request_queue\n+            end\n+          end\n+\n+          ##\n+          # Whether the client has stopped listening for changes.\n+          #\n+          # @example\n+          #   require \"google/cloud/firestore\"\n+          #\n+          #   firestore = Google::Cloud::Firestore.new\n+          #\n+          #   # Create a query\n+          #   query = firestore.col(:cities).order(:population, :desc)\n+          #\n+          #   listener = query.listen do |snapshot|\n+          #     puts \"The query snapshot has #{snapshot.docs.count} documents \"\n+          #     puts \"and has #{snapshot.changes.count} changes.\"\n+          #   end\n+          #\n+          #   # Checks if the listener is stopped.\n+          #   listener.stopped? #=> false\n+          #\n+          #   # When ready, stop the listen operation and close the stream.\n+          #   listener.stop\n+          #\n+          #   # Checks if the listener is stopped.\n+          #   listener.stopped? #=> true\n+          #\n+          def stopped?\n+            synchronize { @stopped }\n+          end\n+\n+          private\n+\n+          def send_callback query_snp\n+            @callback.call query_snp\n+          end\n+\n+          def start_listening!\n+            # create new background thread to handle the stream's enumerator\n+            @background_thread = Thread.new { background_run }\n+          end\n+\n+          # @private\n+          class RestartStream < StandardError; end\n+\n+          # rubocop:disable all\n+\n+          def background_run\n+            # Don't allow a stream to restart if already stopped\n+            return if synchronize { @stopped }\n+\n+            @backoff ||= { current: 0, delay: 1.0, max: 5, mod: 1.3 }\n+\n+            # Reuse inventory if one already exists\n+            # Even though this uses an @var, no need to synchronize\n+            @inventory ||= Inventory.new(@client, @query)\n+            @inventory.restart\n+\n+            # Send stop if already running\n+            synchronize do\n+              @request_queue.push self if @request_queue\n+            end\n+\n+            # Customize the provided initial listen request\n+            init_listen_req = @init_listen_req.dup.tap do |req|\n+              req.add_target.resume_token = String(@inventory.resume_token)\n+              req.add_target.read_time = \\\n+                Convert.time_to_timestamp(@inventory.read_time)\n+              req.add_target.target_id = 0x42\n+            end\n+\n+            # Always create a new enum queue\n+            synchronize do\n+              @request_queue = EnumeratorQueue.new self\n+              @request_queue.push init_listen_req\n+            end\n+\n+            # Not an @var, we get a new enum each time\n+            enum = synchronize do\n+              @client.service.listen @request_queue.each\n+            end\n+\n+            loop do\n+\n+              # Break loop, close thread if stopped\n+              break if synchronize { @stopped }\n+\n+              begin\n+                # Cannot syncronize the enumerator, causes deadlock\n+                response = enum.next\n+\n+                case response.response_type\n+                when :target_change\n+                  case response.target_change.target_change_type\n+                  when :NO_CHANGE\n+                    # No change has occurred. Used only to send an updated\n+                    # +resume_token+.\n+\n+                    @inventory.persist(\n+                      response.target_change.resume_token,\n+                      Convert.timestamp_to_time(\n+                        response.target_change.read_time\n+                      )\n+                    )\n+\n+                    if @inventory.current? && @inventory.changes?\n+                      synchronize do\n+                        send_callback @inventory.build_query_snapshot\n+                      end\n+                    end\n+                  when :CURRENT\n+                    # The targets reflect all changes committed before the targets\n+                    # were added to the stream.\n+                    #\n+                    # This will be sent after or with a +read_time+ that is\n+                    # greater than or equal to the time at which the targets were\n+                    # added.\n+                    #\n+                    # Listeners can wait for this change if read-after-write\n+                    # semantics are desired.\n+\n+                    @inventory.persist(\n+                      response.target_change.resume_token,\n+                      Convert.timestamp_to_time(\n+                        response.target_change.read_time\n+                      )\n+                    )\n+\n+                    @inventory.current = true\n+                  when :RESET\n+                    # The targets have been reset, and a new initial state for the\n+                    # targets will be returned in subsequent changes.\n+                    #\n+                    # After the initial state is complete, +CURRENT+ will be\n+                    # returned even if the target was previously indicated to be\n+                    # +CURRENT+.\n+\n+                    @inventory.reset\n+                    raise RestartStream # Raise to restart the stream\n+                  end\n+                when :document_change\n+                  # A {Google::Firestore::V1beta1::Document Document} has changed.\n+\n+                  if response.document_change.removed_target_ids.any?\n+                    @inventory.delete response.document_change.document.name\n+                  else\n+                    @inventory.add response.document_change.document\n+                  end\n+                when :document_delete\n+                  # A {Google::Firestore::V1beta1::Document Document} has been\n+                  # deleted.\n+\n+                  @inventory.delete response.document_delete.document\n+                when :document_remove\n+                  # A {Google::Firestore::V1beta1::Document Document} has been\n+                  # removed from a target (because it is no longer relevant to\n+                  # that target).\n+\n+                  @inventory.delete response.document_remove.document\n+                when :filter\n+                  # A filter to apply to the set of documents previously returned\n+                  # for the given target.\n+                  #\n+                  # Returned when documents may have been removed from the given\n+                  # target, but the exact documents are unknown.\n+\n+                  if response.filter.count != @inventory.size","path":"google-cloud-firestore/lib/google/cloud/firestore/watch/listener.rb","position":254,"original_position":254,"commit_id":"1caedb409ffe4bd003da72604cd6641768c3cbc7","original_commit_id":"1caedb409ffe4bd003da72604cd6641768c3cbc7","user":{"login":"schmidt-sebastian","id":19397744,"node_id":"MDQ6VXNlcjE5Mzk3NzQ0","avatar_url":"https://avatars3.githubusercontent.com/u/19397744?v=4","gravatar_id":"","url":"https://api.github.com/users/schmidt-sebastian","html_url":"https://github.com/schmidt-sebastian","followers_url":"https://api.github.com/users/schmidt-sebastian/followers","following_url":"https://api.github.com/users/schmidt-sebastian/following{/other_user}","gists_url":"https://api.github.com/users/schmidt-sebastian/gists{/gist_id}","starred_url":"https://api.github.com/users/schmidt-sebastian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schmidt-sebastian/subscriptions","organizations_url":"https://api.github.com/users/schmidt-sebastian/orgs","repos_url":"https://api.github.com/users/schmidt-sebastian/repos","events_url":"https://api.github.com/users/schmidt-sebastian/events{/privacy}","received_events_url":"https://api.github.com/users/schmidt-sebastian/received_events","type":"User","site_admin":false},"body":"Yes, that would work.","created_at":"2018-08-07T16:30:57Z","updated_at":"2018-08-07T16:30:57Z","html_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202#discussion_r208299933","pull_request_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/comments/208299933"},"html":{"href":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202#discussion_r208299933"},"pull_request":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202"}},"in_reply_to_id":208102640},"pull_request":{"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202","id":203338198,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAzMzM4MTk4","html_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202","diff_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202.diff","patch_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202.patch","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/2202","number":2202,"state":"open","locked":false,"title":"Firestore Watch","user":{"login":"blowmage","id":730,"node_id":"MDQ6VXNlcjczMA==","avatar_url":"https://avatars0.githubusercontent.com/u/730?v=4","gravatar_id":"","url":"https://api.github.com/users/blowmage","html_url":"https://github.com/blowmage","followers_url":"https://api.github.com/users/blowmage/followers","following_url":"https://api.github.com/users/blowmage/following{/other_user}","gists_url":"https://api.github.com/users/blowmage/gists{/gist_id}","starred_url":"https://api.github.com/users/blowmage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blowmage/subscriptions","organizations_url":"https://api.github.com/users/blowmage/orgs","repos_url":"https://api.github.com/users/blowmage/repos","events_url":"https://api.github.com/users/blowmage/events{/privacy}","received_events_url":"https://api.github.com/users/blowmage/received_events","type":"User","site_admin":false},"body":"This PR adds the ability to listen to a document reference or a collection reference/query for changes. A document or query snapshot will be yielded immediately, and each time the contents change.\r\n\r\nYou can use `DocumentReference#listen` to be notified of changes to a single document:\r\n\r\n```ruby\r\nrequire \"google/cloud/firestore\"\r\n\r\nfirestore = Google::Cloud::Firestore.new\r\n\r\n# Get a document reference\r\nnyc_ref = firestore.doc \"cities/NYC\"\r\n\r\nlistener = nyc_ref.listen do |snapshot|\r\n  puts \"The population of #{snapshot[:name]} \"\r\n  puts \"is #{snapshot[:population]}.\"\r\nend\r\n\r\n# When ready, stop the listen operation and close the stream.\r\nlistener.stop\r\n```\r\n\r\nYou can use `Firestore::Query#listen` to be notified of changes to any document contained in the query:\r\n\r\n```ruby\r\nrequire \"google/cloud/firestore\"\r\n\r\nfirestore = Google::Cloud::Firestore.new\r\n\r\n# Create a query\r\nquery = firestore.col(:cities).order(:population, :desc)\r\n\r\nlistener = query.listen do |snapshot|\r\n  puts \"The query snapshot has #{snapshot.docs.count} documents \"\r\n  puts \"and has #{snapshot.changes.count} changes.\"\r\nend\r\n\r\n# When ready, stop the listen operation and close the stream.\r\nlistener.stop\r\n```\r\n\r\nThis is accomplished by the following:\r\n\r\n* Add `DocumentReference#listen` and `Query#listen` methods.\r\n* Add `QuerySnapshot` and `DocumentChange` classes.\r\n* Add `DocumentListener` and `QueryListener` classes.\r\n* `DocumentReference#listen` yields a `DocumentSnapshot` object.\r\n* `Query#listen` yields a `QuerySnapshot` object.\r\n* Both `listen` methods return a listener object (`DocumentListener` or `QueryListener`) that users can use to control the watch stream.","created_at":"2018-07-23T20:44:35Z","updated_at":"2018-08-07T16:30:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a43a587a9c3a8d503cf27e1ffba44c700015df9f","assignee":{"login":"blowmage","id":730,"node_id":"MDQ6VXNlcjczMA==","avatar_url":"https://avatars0.githubusercontent.com/u/730?v=4","gravatar_id":"","url":"https://api.github.com/users/blowmage","html_url":"https://github.com/blowmage","followers_url":"https://api.github.com/users/blowmage/followers","following_url":"https://api.github.com/users/blowmage/following{/other_user}","gists_url":"https://api.github.com/users/blowmage/gists{/gist_id}","starred_url":"https://api.github.com/users/blowmage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blowmage/subscriptions","organizations_url":"https://api.github.com/users/blowmage/orgs","repos_url":"https://api.github.com/users/blowmage/repos","events_url":"https://api.github.com/users/blowmage/events{/privacy}","received_events_url":"https://api.github.com/users/blowmage/received_events","type":"User","site_admin":false},"assignees":[{"login":"blowmage","id":730,"node_id":"MDQ6VXNlcjczMA==","avatar_url":"https://avatars0.githubusercontent.com/u/730?v=4","gravatar_id":"","url":"https://api.github.com/users/blowmage","html_url":"https://github.com/blowmage","followers_url":"https://api.github.com/users/blowmage/followers","following_url":"https://api.github.com/users/blowmage/following{/other_user}","gists_url":"https://api.github.com/users/blowmage/gists{/gist_id}","starred_url":"https://api.github.com/users/blowmage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blowmage/subscriptions","organizations_url":"https://api.github.com/users/blowmage/orgs","repos_url":"https://api.github.com/users/blowmage/repos","events_url":"https://api.github.com/users/blowmage/events{/privacy}","received_events_url":"https://api.github.com/users/blowmage/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"quartzmo","id":205445,"node_id":"MDQ6VXNlcjIwNTQ0NQ==","avatar_url":"https://avatars3.githubusercontent.com/u/205445?v=4","gravatar_id":"","url":"https://api.github.com/users/quartzmo","html_url":"https://github.com/quartzmo","followers_url":"https://api.github.com/users/quartzmo/followers","following_url":"https://api.github.com/users/quartzmo/following{/other_user}","gists_url":"https://api.github.com/users/quartzmo/gists{/gist_id}","starred_url":"https://api.github.com/users/quartzmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quartzmo/subscriptions","organizations_url":"https://api.github.com/users/quartzmo/orgs","repos_url":"https://api.github.com/users/quartzmo/repos","events_url":"https://api.github.com/users/quartzmo/events{/privacy}","received_events_url":"https://api.github.com/users/quartzmo/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":784319857,"node_id":"MDU6TGFiZWw3ODQzMTk4NTc=","url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/labels/api:%20firestore","name":"api: firestore","color":"f8f8f8","default":false},{"id":166382179,"node_id":"MDU6TGFiZWwxNjYzODIxNzk=","url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/labels/cla:%20yes","name":"cla: yes","color":"c2e0c6","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202/commits","review_comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202/comments","review_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/comments{/number}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/2202/comments","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/statuses/1caedb409ffe4bd003da72604cd6641768c3cbc7","head":{"label":"blowmage:firestore-watch","ref":"firestore-watch","sha":"1caedb409ffe4bd003da72604cd6641768c3cbc7","user":{"login":"blowmage","id":730,"node_id":"MDQ6VXNlcjczMA==","avatar_url":"https://avatars0.githubusercontent.com/u/730?v=4","gravatar_id":"","url":"https://api.github.com/users/blowmage","html_url":"https://github.com/blowmage","followers_url":"https://api.github.com/users/blowmage/followers","following_url":"https://api.github.com/users/blowmage/following{/other_user}","gists_url":"https://api.github.com/users/blowmage/gists{/gist_id}","starred_url":"https://api.github.com/users/blowmage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blowmage/subscriptions","organizations_url":"https://api.github.com/users/blowmage/orgs","repos_url":"https://api.github.com/users/blowmage/repos","events_url":"https://api.github.com/users/blowmage/events{/privacy}","received_events_url":"https://api.github.com/users/blowmage/received_events","type":"User","site_admin":false},"repo":{"id":29543910,"node_id":"MDEwOlJlcG9zaXRvcnkyOTU0MzkxMA==","name":"gcloud-ruby","full_name":"blowmage/gcloud-ruby","owner":{"login":"blowmage","id":730,"node_id":"MDQ6VXNlcjczMA==","avatar_url":"https://avatars0.githubusercontent.com/u/730?v=4","gravatar_id":"","url":"https://api.github.com/users/blowmage","html_url":"https://github.com/blowmage","followers_url":"https://api.github.com/users/blowmage/followers","following_url":"https://api.github.com/users/blowmage/following{/other_user}","gists_url":"https://api.github.com/users/blowmage/gists{/gist_id}","starred_url":"https://api.github.com/users/blowmage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blowmage/subscriptions","organizations_url":"https://api.github.com/users/blowmage/orgs","repos_url":"https://api.github.com/users/blowmage/repos","events_url":"https://api.github.com/users/blowmage/events{/privacy}","received_events_url":"https://api.github.com/users/blowmage/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/blowmage/gcloud-ruby","description":"Google Cloud Client Library for Ruby","fork":true,"url":"https://api.github.com/repos/blowmage/gcloud-ruby","forks_url":"https://api.github.com/repos/blowmage/gcloud-ruby/forks","keys_url":"https://api.github.com/repos/blowmage/gcloud-ruby/keys{/key_id}","collaborators_url":"https://api.github.com/repos/blowmage/gcloud-ruby/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/blowmage/gcloud-ruby/teams","hooks_url":"https://api.github.com/repos/blowmage/gcloud-ruby/hooks","issue_events_url":"https://api.github.com/repos/blowmage/gcloud-ruby/issues/events{/number}","events_url":"https://api.github.com/repos/blowmage/gcloud-ruby/events","assignees_url":"https://api.github.com/repos/blowmage/gcloud-ruby/assignees{/user}","branches_url":"https://api.github.com/repos/blowmage/gcloud-ruby/branches{/branch}","tags_url":"https://api.github.com/repos/blowmage/gcloud-ruby/tags","blobs_url":"https://api.github.com/repos/blowmage/gcloud-ruby/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/blowmage/gcloud-ruby/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/blowmage/gcloud-ruby/git/refs{/sha}","trees_url":"https://api.github.com/repos/blowmage/gcloud-ruby/git/trees{/sha}","statuses_url":"https://api.github.com/repos/blowmage/gcloud-ruby/statuses/{sha}","languages_url":"https://api.github.com/repos/blowmage/gcloud-ruby/languages","stargazers_url":"https://api.github.com/repos/blowmage/gcloud-ruby/stargazers","contributors_url":"https://api.github.com/repos/blowmage/gcloud-ruby/contributors","subscribers_url":"https://api.github.com/repos/blowmage/gcloud-ruby/subscribers","subscription_url":"https://api.github.com/repos/blowmage/gcloud-ruby/subscription","commits_url":"https://api.github.com/repos/blowmage/gcloud-ruby/commits{/sha}","git_commits_url":"https://api.github.com/repos/blowmage/gcloud-ruby/git/commits{/sha}","comments_url":"https://api.github.com/repos/blowmage/gcloud-ruby/comments{/number}","issue_comment_url":"https://api.github.com/repos/blowmage/gcloud-ruby/issues/comments{/number}","contents_url":"https://api.github.com/repos/blowmage/gcloud-ruby/contents/{+path}","compare_url":"https://api.github.com/repos/blowmage/gcloud-ruby/compare/{base}...{head}","merges_url":"https://api.github.com/repos/blowmage/gcloud-ruby/merges","archive_url":"https://api.github.com/repos/blowmage/gcloud-ruby/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/blowmage/gcloud-ruby/downloads","issues_url":"https://api.github.com/repos/blowmage/gcloud-ruby/issues{/number}","pulls_url":"https://api.github.com/repos/blowmage/gcloud-ruby/pulls{/number}","milestones_url":"https://api.github.com/repos/blowmage/gcloud-ruby/milestones{/number}","notifications_url":"https://api.github.com/repos/blowmage/gcloud-ruby/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/blowmage/gcloud-ruby/labels{/name}","releases_url":"https://api.github.com/repos/blowmage/gcloud-ruby/releases{/id}","deployments_url":"https://api.github.com/repos/blowmage/gcloud-ruby/deployments","created_at":"2015-01-20T18:09:16Z","updated_at":"2017-09-06T13:14:21Z","pushed_at":"2018-08-07T15:24:25Z","git_url":"git://github.com/blowmage/gcloud-ruby.git","ssh_url":"git@github.com:blowmage/gcloud-ruby.git","clone_url":"https://github.com/blowmage/gcloud-ruby.git","svn_url":"https://github.com/blowmage/gcloud-ruby","homepage":"","size":22182,"stargazers_count":2,"watchers_count":2,"language":"Ruby","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"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":0,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"GoogleCloudPlatform:master","ref":"master","sha":"229cebc9cd0b1b8b8ede93a6900e74d7f2992a89","user":{"login":"GoogleCloudPlatform","id":2810941,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI4MTA5NDE=","avatar_url":"https://avatars0.githubusercontent.com/u/2810941?v=4","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":20343475,"node_id":"MDEwOlJlcG9zaXRvcnkyMDM0MzQ3NQ==","name":"google-cloud-ruby","full_name":"GoogleCloudPlatform/google-cloud-ruby","owner":{"login":"GoogleCloudPlatform","id":2810941,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI4MTA5NDE=","avatar_url":"https://avatars0.githubusercontent.com/u/2810941?v=4","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby","description":"Google Cloud Client Library for Ruby","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/comments{/number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/releases{/id}","deployments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/deployments","created_at":"2014-05-30T21:47:14Z","updated_at":"2018-08-07T16:21:41Z","pushed_at":"2018-08-07T16:21:38Z","git_url":"git://github.com/GoogleCloudPlatform/google-cloud-ruby.git","ssh_url":"git@github.com:GoogleCloudPlatform/google-cloud-ruby.git","clone_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby.git","svn_url":"https://github.com/GoogleCloudPlatform/google-cloud-ruby","homepage":"https://googlecloudplatform.github.io/google-cloud-ruby/","size":46942,"stargazers_count":569,"watchers_count":569,"language":"Ruby","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":218,"mirror_url":null,"archived":false,"open_issues_count":46,"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":218,"open_issues":46,"watchers":569,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202"},"html":{"href":"https://github.com/GoogleCloudPlatform/google-cloud-ruby/pull/2202"},"issue":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/2202"},"comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/issues/2202/comments"},"review_comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202/comments"},"review_comment":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/pulls/2202/commits"},"statuses":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-ruby/statuses/1caedb409ffe4bd003da72604cd6641768c3cbc7"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"schmidt-sebastian"}}