{"action":"created","comment":{"url":"https://api.github.com/repos/flynn/flynn/pulls/comments/28929072","id":28929072,"diff_hunk":"@@ -0,0 +1,574 @@\n+package installer\n+\n+import (\n+\t\"bytes\"\n+\t\"encoding/base64\"\n+\t\"encoding/json\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"net/http\"\n+\t\"net/url\"\n+\t\"sort\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\t\"github.com/flynn/flynn/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws\"\n+\t\"github.com/flynn/flynn/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/gen/cloudformation\"\n+\t\"github.com/flynn/flynn/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/gen/ec2\"\n+\t\"github.com/flynn/flynn/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/gen/route53\"\n+\t\"github.com/flynn/flynn/pkg/awsutil\"\n+\t\"github.com/flynn/flynn/pkg/sshkeygen\"\n+\t\"github.com/flynn/flynn/util/release/types\"\n+)\n+\n+var DisallowedEC2InstanceTypes = []string{\"t1.micro\", \"t2.micro\", \"t2.small\", \"m1.small\"}\n+var DefaultInstanceType = \"m3.medium\"\n+var StackNotFoundError = errors.New(\"Stack does not exist\")\n+\n+func (c *AWSCluster) saveField(field string, value interface{}) error {\n+\tc.cluster.installer.dbMtx.Lock()\n+\tdefer c.cluster.installer.dbMtx.Unlock()\n+\n+\ttx, err := c.cluster.installer.db.Begin()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\t_, err = tx.Exec(fmt.Sprintf(`\n+  UPDATE aws_clusters SET %s = $2 WHERE ClusterID == $1\n+  `, field), c.ClusterID, value)\n+\tif err != nil {\n+\t\ttx.Rollback()\n+\t\treturn err\n+\t}\n+\treturn tx.Commit()\n+}\n+\n+func (c *AWSCluster) SetDefaultsAndValidate() error {\n+\tif c.InstanceType == \"\" {\n+\t\tc.InstanceType = DefaultInstanceType\n+\t}\n+\n+\tif c.VpcCidr == \"\" {\n+\t\tc.VpcCidr = \"10.0.0.0/16\"\n+\t}\n+\n+\tif c.SubnetCidr == \"\" {\n+\t\tc.SubnetCidr = \"10.0.0.0/21\"\n+\t}\n+\n+\tif err := c.validateInputs(); err != nil {\n+\t\treturn err\n+\t}\n+\n+\tif err := c.cluster.SetDefaultsAndValidate(); err != nil {\n+\t\treturn err\n+\t}\n+\n+\tc.ec2 = ec2.New(c.creds, c.Region, nil)\n+\tc.cf = cloudformation.New(c.creds, c.Region, nil)\n+\treturn nil\n+}\n+\n+func (c *AWSCluster) validateInputs() error {\n+\tif c.Region == \"\" {\n+\t\treturn fmt.Errorf(\"No region specified\")\n+\t}\n+\n+\tfor _, t := range DisallowedEC2InstanceTypes {\n+\t\tif c.InstanceType == t {\n+\t\t\treturn fmt.Errorf(\"Unsupported instance type %s\", c.InstanceType)\n+\t\t}\n+\t}\n+\n+\treturn nil\n+}\n+\n+func (c *AWSCluster) Run() {\n+\tgo func() {\n+\t\tdefer func() {\n+\t\t\tc.cluster.handleDone()\n+\t\t}()\n+\n+\t\tsteps := []func() error{\n+\t\t\tc.createKeyPair,\n+\t\t\tc.cluster.allocateDomain,\n+\t\t\tc.fetchImageID,\n+\t\t\tc.createStack,\n+\t\t\tc.fetchStackOutputs,\n+\t\t\tc.configureDNS,\n+\t\t\tc.bootstrap,\n+\t\t}\n+\n+\t\tfor _, step := range steps {\n+\t\t\tif err := step(); err != nil {\n+\t\t\t\tif c.cluster.State != \"deleting\" {\n+\t\t\t\t\tc.cluster.setState(\"error\")\n+\t\t\t\t\tc.cluster.SendError(err)\n+\t\t\t\t}\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t}\n+\n+\t\tc.cluster.setState(\"running\")\n+\n+\t\tif err := c.cluster.configureCLI(); err != nil {\n+\t\t\tc.cluster.SendInstallLogEvent(fmt.Sprintf(\"WARNING: Failed to configure CLI: %s\", err))\n+\t\t}\n+\t}()\n+}\n+\n+func (c *AWSCluster) Delete() {\n+\tc.cf = cloudformation.New(c.creds, c.Region, nil)\n+\tgo func() {\n+\t\tstackEventsSince := time.Now()\n+\t\tc.cluster.setState(\"deleting\")\n+\t\tif err := c.fetchStack(); err != StackNotFoundError {\n+\t\t\tfmt.Println(err)\n+\t\t\tif err := c.cf.DeleteStack(&cloudformation.DeleteStackInput{\n+\t\t\t\tStackName: aws.String(c.StackName),\n+\t\t\t}); err != nil {\n+\t\t\t\tc.cluster.setState(\"error\")\n+\t\t\t\tc.cluster.SendError(fmt.Errorf(\"Unable to delete stack %s: %s\", c.StackName, err))\n+\t\t\t} else {\n+\t\t\t\tif err := c.waitForStackCompletion(\"DELETE\", stackEventsSince); err != nil {\n+\t\t\t\t\tc.cluster.SendError(err)\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif err := c.cluster.RemoveFromDB(); err != nil {\n+\t\t\tc.cluster.SendError(err)\n+\t\t}\n+\t\tc.cluster.sendEvent(&Event{\n+\t\t\tClusterID:   c.cluster.ID,\n+\t\t\tType:        \"cluster_state\",\n+\t\t\tDescription: \"deleted\",\n+\t\t})\n+\t}()\n+}\n+\n+func (c *AWSCluster) loadKeyPair(name string) error {\n+\tkeypair, err := loadSSHKey(name)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tfingerprint, err := awsutil.FingerprintImportedKey(keypair.PrivateKey)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tres, err := c.ec2.DescribeKeyPairs(&ec2.DescribeKeyPairsRequest{\n+\t\tFilters: []ec2.Filter{\n+\t\t\t{\n+\t\t\t\tName:   aws.String(\"fingerprint\"),\n+\t\t\t\tValues: []string{fingerprint},\n+\t\t\t},\n+\t\t},\n+\t})\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tif len(res.KeyPairs) == 0 {\n+\t\treturn errors.New(\"No matching key found\")\n+\t}\n+\tc.cluster.SSHKey = keypair\n+\tfor _, p := range res.KeyPairs {\n+\t\tif *p.KeyName == name {\n+\t\t\tc.cluster.SSHKeyName = name\n+\t\t\treturn nil\n+\t\t}\n+\t}\n+\tc.cluster.SSHKeyName = *res.KeyPairs[0].KeyName\n+\treturn saveSSHKey(c.cluster.SSHKeyName, keypair)\n+}\n+\n+func (c *AWSCluster) createKeyPair() error {\n+\tkeypairName := \"flynn\"\n+\tif c.cluster.SSHKeyName != \"\" {\n+\t\tkeypairName = c.cluster.SSHKeyName\n+\t}\n+\tif err := c.loadKeyPair(keypairName); err == nil {\n+\t\tc.cluster.SendInstallLogEvent(fmt.Sprintf(\"Using saved key pair (%s)\", c.cluster.SSHKeyName))\n+\t\treturn nil\n+\t}\n+\n+\tc.cluster.SendInstallLogEvent(\"Creating key pair\")\n+\tkeypair, err := sshkeygen.Generate()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tenc := base64.StdEncoding\n+\tpublicKeyBytes := make([]byte, enc.EncodedLen(len(keypair.PublicKey)))\n+\tenc.Encode(publicKeyBytes, keypair.PublicKey)\n+\n+\tres, err := c.ec2.ImportKeyPair(&ec2.ImportKeyPairRequest{\n+\t\tKeyName:           aws.String(keypairName),\n+\t\tPublicKeyMaterial: publicKeyBytes,\n+\t})\n+\tif apiErr, ok := err.(aws.APIError); ok && apiErr.Code == \"InvalidKeyPair.Duplicate\" {\n+\t\tif c.cluster.YesNoPrompt(fmt.Sprintf(\"Key pair %s already exists, would you like to delete it?\", keypairName)) {\n+\t\t\tc.cluster.SendInstallLogEvent(\"Deleting key pair\")\n+\t\t\tif err := c.ec2.DeleteKeyPair(&ec2.DeleteKeyPairRequest{\n+\t\t\t\tKeyName: aws.String(keypairName),\n+\t\t\t}); err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t\treturn c.createKeyPair()\n+\t\t} else {\n+\t\t\tfor {\n+\t\t\t\tkeypairName = c.cluster.PromptInput(\"Please enter a new key pair name\")\n+\t\t\t\tif keypairName != \"\" {\n+\t\t\t\t\tc.cluster.SSHKeyName = keypairName\n+\t\t\t\t\treturn c.createKeyPair()\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tc.cluster.SSHKey = keypair\n+\tc.cluster.SSHKeyName = *res.KeyName\n+\n+\terr = saveSSHKey(keypairName, keypair)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\treturn nil\n+}\n+\n+func (c *AWSCluster) fetchImageID() (err error) {\n+\tdefer func() {\n+\t\tif err == nil {\n+\t\t\treturn\n+\t\t}\n+\t\tc.cluster.SendInstallLogEvent(err.Error())\n+\t\tif c.ImageID != \"\" {\n+\t\t\tc.cluster.SendInstallLogEvent(\"Falling back to saved Image ID\")\n+\t\t\terr = nil\n+\t\t\treturn\n+\t\t}\n+\t\treturn\n+\t}()\n+\n+\tc.cluster.SendInstallLogEvent(\"Fetching image manifest\")\n+\n+\tlatestImages, err := c.fetchLatestEC2Images()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tvar imageID string\n+\tfor _, i := range latestImages {\n+\t\tif i.Region == c.Region {\n+\t\t\timageID = i.ID\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif imageID == \"\" {\n+\t\treturn errors.New(fmt.Sprintf(\"No image found for region %s\", c.Region))\n+\t}\n+\tc.ImageID = imageID\n+\tif err := c.saveField(\"ImageID\", imageID); err != nil {\n+\t\treturn err\n+\t}\n+\treturn nil\n+}\n+\n+func (c *AWSCluster) fetchLatestEC2Images() ([]*release.EC2Image, error) {\n+\tclient := &http.Client{}\n+\tresp, err := client.Get(\"https://dl.flynn.io/ec2/images.json\")\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tif resp.StatusCode != http.StatusOK {\n+\t\treturn nil, errors.New(fmt.Sprintf(\"Failed to fetch list of flynn images: %s\", resp.Status))\n+\t}\n+\tdec := json.NewDecoder(resp.Body)\n+\tmanifest := release.EC2Manifest{}\n+\terr = dec.Decode(&manifest)\n+\tif err != nil {","path":"installer/aws_cluster.go","position":289,"original_position":289,"commit_id":"6146ce1851ffedeb7c22410a9d20063241459cfd","original_commit_id":"6146ce1851ffedeb7c22410a9d20063241459cfd","user":{"login":"titanous","id":13026,"avatar_url":"https://avatars.githubusercontent.com/u/13026?v=3","gravatar_id":"","url":"https://api.github.com/users/titanous","html_url":"https://github.com/titanous","followers_url":"https://api.github.com/users/titanous/followers","following_url":"https://api.github.com/users/titanous/following{/other_user}","gists_url":"https://api.github.com/users/titanous/gists{/gist_id}","starred_url":"https://api.github.com/users/titanous/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/titanous/subscriptions","organizations_url":"https://api.github.com/users/titanous/orgs","repos_url":"https://api.github.com/users/titanous/repos","events_url":"https://api.github.com/users/titanous/events{/privacy}","received_events_url":"https://api.github.com/users/titanous/received_events","type":"User","site_admin":false},"body":"```go\r\nif err := json.NewDecoder(resp.Body).Decode(&manifest); err != nil {\r\n```","created_at":"2015-04-23T00:57:48Z","updated_at":"2015-04-23T00:57:48Z","html_url":"https://github.com/flynn/flynn/pull/1471#discussion_r28929072","pull_request_url":"https://api.github.com/repos/flynn/flynn/pulls/1471","_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments/28929072"},"html":{"href":"https://github.com/flynn/flynn/pull/1471#discussion_r28929072"},"pull_request":{"href":"https://api.github.com/repos/flynn/flynn/pulls/1471"}}},"pull_request":{"url":"https://api.github.com/repos/flynn/flynn/pulls/1471","id":33871609,"html_url":"https://github.com/flynn/flynn/pull/1471","diff_url":"https://github.com/flynn/flynn/pull/1471.diff","patch_url":"https://github.com/flynn/flynn/pull/1471.patch","issue_url":"https://api.github.com/repos/flynn/flynn/issues/1471","number":1471,"state":"open","locked":false,"title":"installer: cluster management","user":{"login":"jvatic","id":171040,"avatar_url":"https://avatars.githubusercontent.com/u/171040?v=3","gravatar_id":"","url":"https://api.github.com/users/jvatic","html_url":"https://github.com/jvatic","followers_url":"https://api.github.com/users/jvatic/followers","following_url":"https://api.github.com/users/jvatic/following{/other_user}","gists_url":"https://api.github.com/users/jvatic/gists{/gist_id}","starred_url":"https://api.github.com/users/jvatic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jvatic/subscriptions","organizations_url":"https://api.github.com/users/jvatic/orgs","repos_url":"https://api.github.com/users/jvatic/repos","events_url":"https://api.github.com/users/jvatic/events{/privacy}","received_events_url":"https://api.github.com/users/jvatic/received_events","type":"User","site_admin":false},"body":"![screen shot 2015-04-22 at 11 39 20](https://cloud.githubusercontent.com/assets/171040/7278595/7180c17a-e8e4-11e4-9ac9-8437b6bf5dd2.png)\r\n![screen shot 2015-04-22 at 11 40 00](https://cloud.githubusercontent.com/assets/171040/7278598/763f1d4c-e8e4-11e4-8208-9b8208c353fb.png)","created_at":"2015-04-22T15:44:25Z","updated_at":"2015-04-23T00:57:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ade3e6c415a10805a95e37ea97a793991e8fd946","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/flynn/flynn/pulls/1471/commits","review_comments_url":"https://api.github.com/repos/flynn/flynn/pulls/1471/comments","review_comment_url":"https://api.github.com/repos/flynn/flynn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/flynn/flynn/issues/1471/comments","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/6146ce1851ffedeb7c22410a9d20063241459cfd","head":{"label":"flynn:installer-clusters","ref":"installer-clusters","sha":"6146ce1851ffedeb7c22410a9d20063241459cfd","user":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"repo":{"id":11290232,"name":"flynn","full_name":"flynn/flynn","owner":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flynn/flynn","description":"A next generation open source platform as a service (PaaS)","fork":false,"url":"https://api.github.com/repos/flynn/flynn","forks_url":"https://api.github.com/repos/flynn/flynn/forks","keys_url":"https://api.github.com/repos/flynn/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flynn/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flynn/flynn/teams","hooks_url":"https://api.github.com/repos/flynn/flynn/hooks","issue_events_url":"https://api.github.com/repos/flynn/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/flynn/flynn/events","assignees_url":"https://api.github.com/repos/flynn/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/flynn/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/flynn/flynn/tags","blobs_url":"https://api.github.com/repos/flynn/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flynn/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flynn/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/flynn/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/flynn/flynn/languages","stargazers_url":"https://api.github.com/repos/flynn/flynn/stargazers","contributors_url":"https://api.github.com/repos/flynn/flynn/contributors","subscribers_url":"https://api.github.com/repos/flynn/flynn/subscribers","subscription_url":"https://api.github.com/repos/flynn/flynn/subscription","commits_url":"https://api.github.com/repos/flynn/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/flynn/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/flynn/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/flynn/flynn/issues/comments{/number}","contents_url":"https://api.github.com/repos/flynn/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/flynn/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flynn/flynn/merges","archive_url":"https://api.github.com/repos/flynn/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flynn/flynn/downloads","issues_url":"https://api.github.com/repos/flynn/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/flynn/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/flynn/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/flynn/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flynn/flynn/labels{/name}","releases_url":"https://api.github.com/repos/flynn/flynn/releases{/id}","created_at":"2013-07-09T18:22:06Z","updated_at":"2015-04-23T00:46:24Z","pushed_at":"2015-04-22T21:55:26Z","git_url":"git://github.com/flynn/flynn.git","ssh_url":"git@github.com:flynn/flynn.git","clone_url":"https://github.com/flynn/flynn.git","svn_url":"https://github.com/flynn/flynn","homepage":"https://flynn.io","size":51337,"stargazers_count":3480,"watchers_count":3480,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":244,"mirror_url":null,"open_issues_count":186,"forks":244,"open_issues":186,"watchers":3480,"default_branch":"master"}},"base":{"label":"flynn:installer-clusters-base","ref":"installer-clusters-base","sha":"a8f71f9cbd7be78f1f9ca3be30d3a1748249de40","user":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"repo":{"id":11290232,"name":"flynn","full_name":"flynn/flynn","owner":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flynn/flynn","description":"A next generation open source platform as a service (PaaS)","fork":false,"url":"https://api.github.com/repos/flynn/flynn","forks_url":"https://api.github.com/repos/flynn/flynn/forks","keys_url":"https://api.github.com/repos/flynn/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flynn/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flynn/flynn/teams","hooks_url":"https://api.github.com/repos/flynn/flynn/hooks","issue_events_url":"https://api.github.com/repos/flynn/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/flynn/flynn/events","assignees_url":"https://api.github.com/repos/flynn/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/flynn/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/flynn/flynn/tags","blobs_url":"https://api.github.com/repos/flynn/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flynn/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flynn/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/flynn/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/flynn/flynn/languages","stargazers_url":"https://api.github.com/repos/flynn/flynn/stargazers","contributors_url":"https://api.github.com/repos/flynn/flynn/contributors","subscribers_url":"https://api.github.com/repos/flynn/flynn/subscribers","subscription_url":"https://api.github.com/repos/flynn/flynn/subscription","commits_url":"https://api.github.com/repos/flynn/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/flynn/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/flynn/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/flynn/flynn/issues/comments{/number}","contents_url":"https://api.github.com/repos/flynn/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/flynn/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flynn/flynn/merges","archive_url":"https://api.github.com/repos/flynn/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flynn/flynn/downloads","issues_url":"https://api.github.com/repos/flynn/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/flynn/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/flynn/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/flynn/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flynn/flynn/labels{/name}","releases_url":"https://api.github.com/repos/flynn/flynn/releases{/id}","created_at":"2013-07-09T18:22:06Z","updated_at":"2015-04-23T00:46:24Z","pushed_at":"2015-04-22T21:55:26Z","git_url":"git://github.com/flynn/flynn.git","ssh_url":"git@github.com:flynn/flynn.git","clone_url":"https://github.com/flynn/flynn.git","svn_url":"https://github.com/flynn/flynn","homepage":"https://flynn.io","size":51337,"stargazers_count":3480,"watchers_count":3480,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":244,"mirror_url":null,"open_issues_count":186,"forks":244,"open_issues":186,"watchers":3480,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/1471"},"html":{"href":"https://github.com/flynn/flynn/pull/1471"},"issue":{"href":"https://api.github.com/repos/flynn/flynn/issues/1471"},"comments":{"href":"https://api.github.com/repos/flynn/flynn/issues/1471/comments"},"review_comments":{"href":"https://api.github.com/repos/flynn/flynn/pulls/1471/comments"},"review_comment":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/flynn/flynn/pulls/1471/commits"},"statuses":{"href":"https://api.github.com/repos/flynn/flynn/statuses/6146ce1851ffedeb7c22410a9d20063241459cfd"}}}}