{"action":"created","comment":{"url":"https://api.github.com/repos/docker/docker/pulls/comments/93528186","pull_request_review_id":14058565,"id":93528186,"diff_hunk":"@@ -238,38 +256,211 @@ func (pm *Manager) List() ([]types.Plugin, error) {\n }\n \n // Push pushes a plugin to the store.\n-func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.AuthConfig) error {\n-\tp, err := pm.pluginStore.GetByName(name)\n+func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header, authConfig *types.AuthConfig, outStream io.Writer) error {\n+\tp, err := pm.config.Store.GetV2Plugin(name)\n \tif err != nil {\n \t\treturn err\n \t}\n-\tdest := filepath.Join(pm.libRoot, p.GetID())\n-\tconfig, err := ioutil.ReadFile(filepath.Join(dest, \"config.json\"))\n+\n+\tref, err := reference.ParseNamed(p.Name())\n \tif err != nil {\n-\t\treturn err\n+\t\treturn errors.Wrapf(err, \"plugin has invalid name %v for push\", p.Name())\n \t}\n \n-\tvar dummy types.Plugin\n-\terr = json.Unmarshal(config, &dummy)\n-\tif err != nil {\n-\t\treturn err\n+\tvar po progress.Output\n+\tif outStream != nil {\n+\t\t// Include a buffer so that slow client connections don't affect\n+\t\t// transfer performance.\n+\t\tprogressChan := make(chan progress.Progress, 100)\n+\n+\t\twritesDone := make(chan struct{})\n+\n+\t\tdefer func() {\n+\t\t\tclose(progressChan)\n+\t\t\t<-writesDone\n+\t\t}()\n+\n+\t\tvar cancelFunc context.CancelFunc\n+\t\tctx, cancelFunc = context.WithCancel(ctx)\n+\n+\t\tgo func() {\n+\t\t\tprogressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)\n+\t\t\tclose(writesDone)\n+\t\t}()\n+\n+\t\tpo = progress.ChanOutput(progressChan)\n+\t} else {\n+\t\tpo = progress.DiscardOutput()\n+\t}\n+\n+\t// TODO: replace these with manager\n+\tis := &pluginConfigStore{\n+\t\tpm:     pm,\n+\t\tplugin: p,\n+\t}\n+\tls := &pluginLayerProvider{\n+\t\tpm:     pm,\n+\t\tplugin: p,\n+\t}\n+\trs := &pluginReference{\n+\t\tname:     ref,\n+\t\tpluginID: p.Config,\n+\t}\n+\n+\tuploadManager := xfer.NewLayerUploadManager(3)\n+\n+\timagePushConfig := &distribution.ImagePushConfig{\n+\t\tConfig: distribution.Config{\n+\t\t\tMetaHeaders:      metaHeader,\n+\t\t\tAuthConfig:       authConfig,\n+\t\t\tProgressOutput:   po,\n+\t\t\tRegistryService:  pm.config.RegistryService,\n+\t\t\tReferenceStore:   rs,\n+\t\t\tImageEventLogger: pm.config.LogPluginEvent,\n+\t\t\tImageStore:       is,\n+\t\t\tRequireSchema2:   true,\n+\t\t},\n+\t\tConfigMediaType: schema2.MediaTypePluginConfig,\n+\t\tLayerStore:      ls,\n+\t\tUploadManager:   uploadManager,\n+\t}\n+\n+\treturn distribution.Push(ctx, ref, imagePushConfig)\n+}\n+\n+type pluginReference struct {\n+\tname     reference.Named\n+\tpluginID digest.Digest\n+}\n+\n+func (r *pluginReference) References(id digest.Digest) []reference.Named {\n+\tif r.pluginID != id {\n+\t\treturn nil\n \t}\n+\treturn []reference.Named{r.name}\n+}\n \n-\trootfs, err := archive.Tar(p.Rootfs, archive.Gzip)\n+func (r *pluginReference) ReferencesByName(ref reference.Named) []reference.Association {\n+\treturn []reference.Association{\n+\t\t{\n+\t\t\tRef: r.name,\n+\t\t\tID:  r.pluginID,\n+\t\t},\n+\t}\n+}\n+\n+func (r *pluginReference) Get(ref reference.Named) (digest.Digest, error) {\n+\tif r.name.String() != ref.String() {\n+\t\treturn digest.Digest(\"\"), reference.ErrDoesNotExist\n+\t}\n+\treturn r.pluginID, nil\n+}\n+\n+func (r *pluginReference) AddTag(ref reference.Named, id digest.Digest, force bool) error {\n+\t// Read only, ignore\n+\treturn nil\n+}\n+func (r *pluginReference) AddDigest(ref reference.Canonical, id digest.Digest, force bool) error {\n+\t// Read only, ignore\n+\treturn nil\n+}\n+func (r *pluginReference) Delete(ref reference.Named) (bool, error) {\n+\t// Read only, ignore\n+\treturn false, nil\n+}\n+\n+type pluginConfigStore struct {\n+\tpm     *Manager\n+\tplugin *v2.Plugin\n+}\n+\n+func (s *pluginConfigStore) Put([]byte) (digest.Digest, error) {\n+\treturn digest.Digest(\"\"), errors.New(\"cannot store config on push\")\n+}\n+\n+func (s *pluginConfigStore) Get(d digest.Digest) ([]byte, error) {\n+\tif s.plugin.Config != d {\n+\t\treturn nil, errors.New(\"plugin not found\")\n+\t}\n+\trwc, err := s.pm.blobStore.Get(d)\n \tif err != nil {\n-\t\treturn err\n+\t\treturn nil, err\n+\t}\n+\tdefer rwc.Close()\n+\treturn ioutil.ReadAll(rwc)\n+}\n+\n+func (s *pluginConfigStore) RootFSFromConfig(c []byte) (*image.RootFS, error) {\n+\treturn configToRootFS(c)\n+}\n+\n+type pluginLayerProvider struct {\n+\tpm     *Manager\n+\tplugin *v2.Plugin\n+}\n+\n+func (p *pluginLayerProvider) Get(id layer.ChainID) (distribution.PushLayer, error) {\n+\trootfs := rootFSFromPlugin(p.plugin.PluginObj.Config.Rootfs)\n+\tvar i int\n+\tfor i = 0; i < len(rootfs.DiffIDs); i++ {\n+\t\tif layer.CreateChainID(rootfs.DiffIDs[i:]) == id {\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif i == len(rootfs.DiffIDs) {\n+\t\treturn nil, errors.New(\"layer not found\")\n+\t}\n+\treturn &pluginLayer{\n+\t\tpm:      p.pm,\n+\t\tdiffIDs: rootfs.DiffIDs[i:],\n+\t\tblobs:   p.plugin.Blobsums[i:],\n+\t}, nil\n+}\n+\n+type pluginLayer struct {\n+\tpm      *Manager\n+\tdiffIDs []layer.DiffID\n+\tblobs   []digest.Digest\n+}\n+\n+func (l *pluginLayer) ChainID() layer.ChainID {\n+\treturn layer.CreateChainID(l.diffIDs)","path":"plugin/backend_linux.go","position":495,"original_position":495,"commit_id":"fc8cc8736a250c674847b03ba36a36bd22f3b4ad","original_commit_id":"fc8cc8736a250c674847b03ba36a36bd22f3b4ad","user":{"login":"aaronlehmann","id":10601430,"avatar_url":"https://avatars.githubusercontent.com/u/10601430?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlehmann","html_url":"https://github.com/aaronlehmann","followers_url":"https://api.github.com/users/aaronlehmann/followers","following_url":"https://api.github.com/users/aaronlehmann/following{/other_user}","gists_url":"https://api.github.com/users/aaronlehmann/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlehmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlehmann/subscriptions","organizations_url":"https://api.github.com/users/aaronlehmann/orgs","repos_url":"https://api.github.com/users/aaronlehmann/repos","events_url":"https://api.github.com/users/aaronlehmann/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlehmann/received_events","type":"User","site_admin":false},"body":"From the other methods, it looks like the DiffIDs are stored in reverse order (top layer first), but if that's the case, `CreateChainID` won't work correctly on this slice. `CreateChainID` treats the first item in the slice as the parent of all the others.\r\n\r\nI think it's better to store the bottom layer first, like the image `RootFS` does. But I might be missing something here.","created_at":"2016-12-21T22:01:16Z","updated_at":"2016-12-21T22:01:16Z","html_url":"https://github.com/docker/docker/pull/29487#discussion_r93528186","pull_request_url":"https://api.github.com/repos/docker/docker/pulls/29487","_links":{"self":{"href":"https://api.github.com/repos/docker/docker/pulls/comments/93528186"},"html":{"href":"https://github.com/docker/docker/pull/29487#discussion_r93528186"},"pull_request":{"href":"https://api.github.com/repos/docker/docker/pulls/29487"}}},"pull_request":{"url":"https://api.github.com/repos/docker/docker/pulls/29487","id":98375353,"html_url":"https://github.com/docker/docker/pull/29487","diff_url":"https://github.com/docker/docker/pull/29487.diff","patch_url":"https://github.com/docker/docker/pull/29487.patch","issue_url":"https://api.github.com/repos/docker/docker/issues/29487","number":29487,"state":"open","locked":false,"title":"Plugins content addressability","user":{"login":"tonistiigi","id":585223,"avatar_url":"https://avatars.githubusercontent.com/u/585223?v=3","gravatar_id":"","url":"https://api.github.com/users/tonistiigi","html_url":"https://github.com/tonistiigi","followers_url":"https://api.github.com/users/tonistiigi/followers","following_url":"https://api.github.com/users/tonistiigi/following{/other_user}","gists_url":"https://api.github.com/users/tonistiigi/gists{/gist_id}","starred_url":"https://api.github.com/users/tonistiigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tonistiigi/subscriptions","organizations_url":"https://api.github.com/users/tonistiigi/orgs","repos_url":"https://api.github.com/users/tonistiigi/repos","events_url":"https://api.github.com/users/tonistiigi/events{/privacy}","received_events_url":"https://api.github.com/users/tonistiigi/received_events","type":"User","site_admin":false},"body":"This addresses:\r\n- plugin distribution is moved to a shared stack with images. This fixes quirks with previous implementation including pull-by-digest, content verification and progressbars.\r\n- creates immutable plugin config for configuration that matches schema2 requirements. Hash of this config defines the whole distributable part of the config.\r\n- Ensures data being pushed is the same that was created/pulled so that plugin can't leak anything in there.\r\n- Keeps immutable distribution artifacts in blobstore and uses that for the data that is  pushed.\r\n- Runs the init layer setup on every plugin start to match the safety guarantees of containers\r\n- Fixes some possible breakouts caused by unsafe filesystem accesses or extraction.\r\n- Verifies the tar sent on `plugin create` and splits it up to a config and rootfs.\r\n- Adds `docker install --alias` to control the name of the plugin.\r\n- Uses normalized references for default names to avoid collisions when using default hosts/tags.\r\n- Some refactoring of the plugin manager to support the change, like removing the singleton manager and adding manager config stuct.\r\n\r\nDoes not address:\r\n- Runtime related refactoring like removing the controller and `Store` have been left out\r\n- Likely concurrency problems with manager commands(except create/push/pull).\r\n\r\n@anusha-ragunathan @tiborvass @vieux","created_at":"2016-12-16T17:45:40Z","updated_at":"2016-12-21T22:01:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c2dc3271fc1e63837ebca3ea9bd8ee32e45028ee","assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/docker/docker/milestones/56","html_url":"https://github.com/docker/docker/milestone/56","labels_url":"https://api.github.com/repos/docker/docker/milestones/56/labels","id":1839404,"number":56,"title":"1.13.0","description":"","creator":{"login":"thaJeztah","id":1804568,"avatar_url":"https://avatars.githubusercontent.com/u/1804568?v=3","gravatar_id":"","url":"https://api.github.com/users/thaJeztah","html_url":"https://github.com/thaJeztah","followers_url":"https://api.github.com/users/thaJeztah/followers","following_url":"https://api.github.com/users/thaJeztah/following{/other_user}","gists_url":"https://api.github.com/users/thaJeztah/gists{/gist_id}","starred_url":"https://api.github.com/users/thaJeztah/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thaJeztah/subscriptions","organizations_url":"https://api.github.com/users/thaJeztah/orgs","repos_url":"https://api.github.com/users/thaJeztah/repos","events_url":"https://api.github.com/users/thaJeztah/events{/privacy}","received_events_url":"https://api.github.com/users/thaJeztah/received_events","type":"User","site_admin":false},"open_issues":101,"closed_issues":1273,"state":"open","created_at":"2016-06-20T22:51:25Z","updated_at":"2016-12-21T20:47:18Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/docker/docker/pulls/29487/commits","review_comments_url":"https://api.github.com/repos/docker/docker/pulls/29487/comments","review_comment_url":"https://api.github.com/repos/docker/docker/pulls/comments{/number}","comments_url":"https://api.github.com/repos/docker/docker/issues/29487/comments","statuses_url":"https://api.github.com/repos/docker/docker/statuses/fc8cc8736a250c674847b03ba36a36bd22f3b4ad","head":{"label":"tonistiigi:plugins-rework","ref":"plugins-rework","sha":"fc8cc8736a250c674847b03ba36a36bd22f3b4ad","user":{"login":"tonistiigi","id":585223,"avatar_url":"https://avatars.githubusercontent.com/u/585223?v=3","gravatar_id":"","url":"https://api.github.com/users/tonistiigi","html_url":"https://github.com/tonistiigi","followers_url":"https://api.github.com/users/tonistiigi/followers","following_url":"https://api.github.com/users/tonistiigi/following{/other_user}","gists_url":"https://api.github.com/users/tonistiigi/gists{/gist_id}","starred_url":"https://api.github.com/users/tonistiigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tonistiigi/subscriptions","organizations_url":"https://api.github.com/users/tonistiigi/orgs","repos_url":"https://api.github.com/users/tonistiigi/repos","events_url":"https://api.github.com/users/tonistiigi/events{/privacy}","received_events_url":"https://api.github.com/users/tonistiigi/received_events","type":"User","site_admin":false},"repo":{"id":19074395,"name":"docker","full_name":"tonistiigi/docker","owner":{"login":"tonistiigi","id":585223,"avatar_url":"https://avatars.githubusercontent.com/u/585223?v=3","gravatar_id":"","url":"https://api.github.com/users/tonistiigi","html_url":"https://github.com/tonistiigi","followers_url":"https://api.github.com/users/tonistiigi/followers","following_url":"https://api.github.com/users/tonistiigi/following{/other_user}","gists_url":"https://api.github.com/users/tonistiigi/gists{/gist_id}","starred_url":"https://api.github.com/users/tonistiigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tonistiigi/subscriptions","organizations_url":"https://api.github.com/users/tonistiigi/orgs","repos_url":"https://api.github.com/users/tonistiigi/repos","events_url":"https://api.github.com/users/tonistiigi/events{/privacy}","received_events_url":"https://api.github.com/users/tonistiigi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tonistiigi/docker","description":"Docker - the open-source application container engine","fork":true,"url":"https://api.github.com/repos/tonistiigi/docker","forks_url":"https://api.github.com/repos/tonistiigi/docker/forks","keys_url":"https://api.github.com/repos/tonistiigi/docker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tonistiigi/docker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tonistiigi/docker/teams","hooks_url":"https://api.github.com/repos/tonistiigi/docker/hooks","issue_events_url":"https://api.github.com/repos/tonistiigi/docker/issues/events{/number}","events_url":"https://api.github.com/repos/tonistiigi/docker/events","assignees_url":"https://api.github.com/repos/tonistiigi/docker/assignees{/user}","branches_url":"https://api.github.com/repos/tonistiigi/docker/branches{/branch}","tags_url":"https://api.github.com/repos/tonistiigi/docker/tags","blobs_url":"https://api.github.com/repos/tonistiigi/docker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tonistiigi/docker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tonistiigi/docker/git/refs{/sha}","trees_url":"https://api.github.com/repos/tonistiigi/docker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tonistiigi/docker/statuses/{sha}","languages_url":"https://api.github.com/repos/tonistiigi/docker/languages","stargazers_url":"https://api.github.com/repos/tonistiigi/docker/stargazers","contributors_url":"https://api.github.com/repos/tonistiigi/docker/contributors","subscribers_url":"https://api.github.com/repos/tonistiigi/docker/subscribers","subscription_url":"https://api.github.com/repos/tonistiigi/docker/subscription","commits_url":"https://api.github.com/repos/tonistiigi/docker/commits{/sha}","git_commits_url":"https://api.github.com/repos/tonistiigi/docker/git/commits{/sha}","comments_url":"https://api.github.com/repos/tonistiigi/docker/comments{/number}","issue_comment_url":"https://api.github.com/repos/tonistiigi/docker/issues/comments{/number}","contents_url":"https://api.github.com/repos/tonistiigi/docker/contents/{+path}","compare_url":"https://api.github.com/repos/tonistiigi/docker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tonistiigi/docker/merges","archive_url":"https://api.github.com/repos/tonistiigi/docker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tonistiigi/docker/downloads","issues_url":"https://api.github.com/repos/tonistiigi/docker/issues{/number}","pulls_url":"https://api.github.com/repos/tonistiigi/docker/pulls{/number}","milestones_url":"https://api.github.com/repos/tonistiigi/docker/milestones{/number}","notifications_url":"https://api.github.com/repos/tonistiigi/docker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tonistiigi/docker/labels{/name}","releases_url":"https://api.github.com/repos/tonistiigi/docker/releases{/id}","deployments_url":"https://api.github.com/repos/tonistiigi/docker/deployments","created_at":"2014-04-23T15:15:03Z","updated_at":"2014-07-24T21:22:45Z","pushed_at":"2016-12-21T19:30:11Z","git_url":"git://github.com/tonistiigi/docker.git","ssh_url":"git@github.com:tonistiigi/docker.git","clone_url":"https://github.com/tonistiigi/docker.git","svn_url":"https://github.com/tonistiigi/docker","homepage":"http://www.docker.io","size":118909,"stargazers_count":0,"watchers_count":0,"language":"Go","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":"docker:master","ref":"master","sha":"288e55c09b252e02b5201e7d2f2bf45a323d8105","user":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"repo":{"id":7691631,"name":"docker","full_name":"docker/docker","owner":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/docker/docker","description":"Docker - the open-source application container engine","fork":false,"url":"https://api.github.com/repos/docker/docker","forks_url":"https://api.github.com/repos/docker/docker/forks","keys_url":"https://api.github.com/repos/docker/docker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/docker/docker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/docker/docker/teams","hooks_url":"https://api.github.com/repos/docker/docker/hooks","issue_events_url":"https://api.github.com/repos/docker/docker/issues/events{/number}","events_url":"https://api.github.com/repos/docker/docker/events","assignees_url":"https://api.github.com/repos/docker/docker/assignees{/user}","branches_url":"https://api.github.com/repos/docker/docker/branches{/branch}","tags_url":"https://api.github.com/repos/docker/docker/tags","blobs_url":"https://api.github.com/repos/docker/docker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/docker/docker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/docker/docker/git/refs{/sha}","trees_url":"https://api.github.com/repos/docker/docker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/docker/docker/statuses/{sha}","languages_url":"https://api.github.com/repos/docker/docker/languages","stargazers_url":"https://api.github.com/repos/docker/docker/stargazers","contributors_url":"https://api.github.com/repos/docker/docker/contributors","subscribers_url":"https://api.github.com/repos/docker/docker/subscribers","subscription_url":"https://api.github.com/repos/docker/docker/subscription","commits_url":"https://api.github.com/repos/docker/docker/commits{/sha}","git_commits_url":"https://api.github.com/repos/docker/docker/git/commits{/sha}","comments_url":"https://api.github.com/repos/docker/docker/comments{/number}","issue_comment_url":"https://api.github.com/repos/docker/docker/issues/comments{/number}","contents_url":"https://api.github.com/repos/docker/docker/contents/{+path}","compare_url":"https://api.github.com/repos/docker/docker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/docker/docker/merges","archive_url":"https://api.github.com/repos/docker/docker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/docker/docker/downloads","issues_url":"https://api.github.com/repos/docker/docker/issues{/number}","pulls_url":"https://api.github.com/repos/docker/docker/pulls{/number}","milestones_url":"https://api.github.com/repos/docker/docker/milestones{/number}","notifications_url":"https://api.github.com/repos/docker/docker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/docker/docker/labels{/name}","releases_url":"https://api.github.com/repos/docker/docker/releases{/id}","deployments_url":"https://api.github.com/repos/docker/docker/deployments","created_at":"2013-01-18T18:10:57Z","updated_at":"2016-12-21T20:22:48Z","pushed_at":"2016-12-21T21:54:20Z","git_url":"git://github.com/docker/docker.git","ssh_url":"git@github.com:docker/docker.git","clone_url":"https://github.com/docker/docker.git","svn_url":"https://github.com/docker/docker","homepage":"http://www.docker.com","size":119030,"stargazers_count":38035,"watchers_count":38035,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11341,"mirror_url":null,"open_issues_count":2054,"forks":11341,"open_issues":2054,"watchers":38035,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/docker/docker/pulls/29487"},"html":{"href":"https://github.com/docker/docker/pull/29487"},"issue":{"href":"https://api.github.com/repos/docker/docker/issues/29487"},"comments":{"href":"https://api.github.com/repos/docker/docker/issues/29487/comments"},"review_comments":{"href":"https://api.github.com/repos/docker/docker/pulls/29487/comments"},"review_comment":{"href":"https://api.github.com/repos/docker/docker/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/docker/docker/pulls/29487/commits"},"statuses":{"href":"https://api.github.com/repos/docker/docker/statuses/fc8cc8736a250c674847b03ba36a36bd22f3b4ad"}}}}
{"actor":{"display_login":"aaronlehmann"}}