{"action":"created","comment":{"url":"https://api.github.com/repos/openshift/library-go/pulls/comments/240521016","pull_request_review_id":183567751,"id":240521016,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MDUyMTAxNg==","diff_hunk":"@@ -0,0 +1,296 @@\n+package prune\n+\n+import (\n+\t\"fmt\"\n+\t\"os\"\n+\t\"sort\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\t\"github.com/golang/glog\"\n+\n+\tcorev1 \"k8s.io/api/core/v1\"\n+\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n+\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n+\t\"k8s.io/apimachinery/pkg/runtime/schema\"\n+\tutilruntime \"k8s.io/apimachinery/pkg/util/runtime\"\n+\t\"k8s.io/apimachinery/pkg/util/wait\"\n+\t\"k8s.io/client-go/dynamic\"\n+\t\"k8s.io/client-go/kubernetes\"\n+\t\"k8s.io/client-go/tools/cache\"\n+\t\"k8s.io/client-go/util/workqueue\"\n+\n+\toperatorv1 \"github.com/openshift/api/operator/v1\"\n+\t\"github.com/openshift/library-go/pkg/operator/events\"\n+\t\"github.com/openshift/library-go/pkg/operator/resource/resourceread\"\n+\t\"github.com/openshift/library-go/pkg/operator/staticpod/controller/common\"\n+)\n+\n+type PruneController struct {\n+\ttargetNamespace, podResourcePrefix          string\n+\tfailedRevisionLimit, succeededRevisionLimit int\n+\n+\t// command is the string to use for the pruning pod command\n+\tcommand []string\n+\t// queue only ever has one item, but it has nice error handling backoff/retry semantics\n+\tqueue workqueue.RateLimitingInterface\n+\t// prunerPodImageFn returns the image name for the installer pod\n+\tprunerPodImageFn func() string\n+\n+\toperatorConfigClient common.OperatorClient\n+\n+\tkubeClient    kubernetes.Interface\n+\teventRecorder events.Recorder\n+\n+\tdynamicClient      dynamic.Interface\n+\toperatorConfigGVR  schema.GroupVersionResource\n+\toperatorConfigName string\n+}\n+\n+const (\n+\tpruneControllerWorkQueueKey = \"key\"\n+\tstatusConfigMapName         = \"revision-status\"\n+\tdefaultResourceDir          = \"/etc/kubernetes/static-pod-resources\"\n+\tprunerPodName               = \"revision-pruner\"\n+)\n+\n+func NewPruneController(\n+\ttargetNamespace string,\n+\tpodResourcePrefix string,\n+\tcommand []string,\n+\tkubeClient kubernetes.Interface,\n+\toperatorConfigClient common.OperatorClient,\n+\teventRecorder events.Recorder,\n+\tdynamicClient dynamic.Interface,\n+\toperatorConfigGVR schema.GroupVersionResource,\n+\toperatorConfigName string,\n+) *PruneController {\n+\tc := &PruneController{\n+\t\ttargetNamespace:        targetNamespace,\n+\t\tpodResourcePrefix:      podResourcePrefix,\n+\t\tcommand:                command,\n+\t\tfailedRevisionLimit:    0,\n+\t\tsucceededRevisionLimit: 0,\n+\n+\t\toperatorConfigClient: operatorConfigClient,\n+\t\tkubeClient:           kubeClient,\n+\t\teventRecorder:        eventRecorder,\n+\n+\t\tdynamicClient:      dynamicClient,\n+\t\toperatorConfigGVR:  operatorConfigGVR,\n+\t\toperatorConfigName: operatorConfigName,\n+\n+\t\tqueue:            workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), \"PruneController\"),\n+\t\tprunerPodImageFn: getPrunerPodImageFromEnv,\n+\t}\n+\n+\toperatorConfigClient.Informer().AddEventHandler(c.eventHandler())\n+\n+\treturn c\n+}\n+\n+func (c *PruneController) syncRevisionLimits() error {\n+\tconfig, err := c.dynamicClient.Resource(c.operatorConfigGVR).Get(c.operatorConfigName, metav1.GetOptions{})\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\trevisionLimits, ok, err := unstructured.NestedMap(config.Object, \"spec\", \"operatorRevisionLimit\")\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tif ok {\n+\t\tif val, set := revisionLimits[\"failed\"]; set {\n+\t\t\tc.failedRevisionLimit = val.(int)\n+\t\t}\n+\t\tif val, set := revisionLimits[\"succeeded\"]; set {\n+\t\t\tc.succeededRevisionLimit = val.(int)\n+\t\t}\n+\t}\n+\treturn nil\n+}\n+\n+func (c *PruneController) pruneRevisionHistory(operatorStatus *operatorv1.StaticPodOperatorStatus, resourceDir string) error {\n+\tvar succeededRevisionIDs, failedRevisionIDs []int\n+\n+\tconfigMaps, err := c.kubeClient.CoreV1().ConfigMaps(c.targetNamespace).List(metav1.ListOptions{})\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tfor _, configMap := range configMaps.Items {\n+\t\tif strings.HasPrefix(configMap.Name, statusConfigMapName) {\n+\t\t\tif revision, ok := configMap.Data[\"revision\"]; ok {\n+\t\t\t\trevisionID, err := strconv.Atoi(revision)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn err\n+\t\t\t\t}\n+\t\t\t\tswitch configMap.Data[\"phase\"] {\n+\t\t\t\tcase string(corev1.PodSucceeded):\n+\t\t\t\t\tsucceededRevisionIDs = append(succeededRevisionIDs, revisionID)\n+\t\t\t\tcase string(corev1.PodFailed):\n+\t\t\t\t\tfailedRevisionIDs = append(failedRevisionIDs, revisionID)\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tsort.Ints(succeededRevisionIDs)\n+\tsort.Ints(failedRevisionIDs)\n+\n+\t// Get list of protected IDs\n+\tprotectedSucceededRevisionIDs := succeededRevisionIDs[revisionKeyToStart(len(succeededRevisionIDs), c.succeededRevisionLimit):]\n+\tprotectedFailedRevisionIDs := failedRevisionIDs[revisionKeyToStart(len(failedRevisionIDs), c.failedRevisionLimit):]\n+\n+\texcludedIDs := make([]int, 0, len(protectedSucceededRevisionIDs)+len(protectedFailedRevisionIDs))\n+\texcludedIDs = append(excludedIDs, protectedSucceededRevisionIDs...)\n+\texcludedIDs = append(excludedIDs, protectedFailedRevisionIDs...)\n+\tsort.Ints(excludedIDs)\n+\n+\t// Run pruning pod on each node and pin it to that node\n+\tfor _, nodeStatus := range operatorStatus.NodeStatuses {\n+\t\terr = c.ensurePrunePod(prunerPodName, nodeStatus.NodeName, excludedIDs[len(excludedIDs)-1], excludedIDs, nodeStatus.TargetRevision)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t}\n+\treturn nil\n+}\n+\n+func revisionKeyToStart(length, limit int) int {\n+\tif length > limit {\n+\t\treturn length - limit\n+\t}\n+\treturn 0\n+}\n+\n+func (c *PruneController) ensurePrunePod(podName, nodeName string, maxEligibleRevision int, protectedRevisions []int, revision int32) error {\n+\trequired := resourceread.ReadPodV1OrDie([]byte(prunerPod))\n+\trequired.Name = fmt.Sprintf(\"%s-%d-%s\", podName, revision, nodeName)\n+\trequired.Namespace = c.targetNamespace\n+\trequired.Spec.NodeName = nodeName\n+\trequired.Spec.Containers[0].Image = c.prunerPodImageFn()\n+\trequired.Spec.Containers[0].Command = c.command\n+\trequired.Spec.Containers[0].Args = append(required.Spec.Containers[0].Args,\n+\t\tfmt.Sprintf(\"-v=%d\", 4),\n+\t\tfmt.Sprintf(\"--max-eligible-id=%d\", maxEligibleRevision),\n+\t\tfmt.Sprintf(\"--protected-ids=%s\", revisionsToString(protectedRevisions)),\n+\t\tfmt.Sprintf(\"--resource-dir=%s\", defaultResourceDir),\n+\t\tfmt.Sprintf(\"--static-pod-name=%s\", c.podResourcePrefix),\n+\t)\n+\n+\tif _, err := c.kubeClient.CoreV1().Pods(c.targetNamespace).Create(required); err != nil && !apierrors.IsAlreadyExists(err) {\n+\t\tc.eventRecorder.Eventf(\"PrunePodFailed\", \"Failed to create pod for %s: %v\", resourceread.WritePodV1OrDie(required), err)\n+\t\treturn err\n+\t}\n+\treturn nil\n+}\n+\n+func revisionsToString(revisions []int) string {\n+\trevisionString := \"\"\n+\tif len(revisions) > 0 {\n+\t\tfor i := 0; i < len(revisions)-1; i++ {\n+\t\t\trevisionString = fmt.Sprintf(\"%s,%d\", revisionString, revisions[i])","path":"pkg/operator/staticpod/controller/prune/prune_controller.go","position":194,"original_position":194,"commit_id":"9d04225504720b2e5c146d8d592c10c04dff2475","original_commit_id":"9d04225504720b2e5c146d8d592c10c04dff2475","user":{"login":"mfojtik","id":44136,"node_id":"MDQ6VXNlcjQ0MTM2","avatar_url":"https://avatars2.githubusercontent.com/u/44136?v=4","gravatar_id":"","url":"https://api.github.com/users/mfojtik","html_url":"https://github.com/mfojtik","followers_url":"https://api.github.com/users/mfojtik/followers","following_url":"https://api.github.com/users/mfojtik/following{/other_user}","gists_url":"https://api.github.com/users/mfojtik/gists{/gist_id}","starred_url":"https://api.github.com/users/mfojtik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mfojtik/subscriptions","organizations_url":"https://api.github.com/users/mfojtik/orgs","repos_url":"https://api.github.com/users/mfojtik/repos","events_url":"https://api.github.com/users/mfojtik/events{/privacy}","received_events_url":"https://api.github.com/users/mfojtik/received_events","type":"User","site_admin":false},"body":"this almost looks like you want to use `strings.Join` ? ;-)","created_at":"2018-12-11T09:04:19Z","updated_at":"2018-12-11T09:04:19Z","html_url":"https://github.com/openshift/library-go/pull/146#discussion_r240521016","pull_request_url":"https://api.github.com/repos/openshift/library-go/pulls/146","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/openshift/library-go/pulls/comments/240521016"},"html":{"href":"https://github.com/openshift/library-go/pull/146#discussion_r240521016"},"pull_request":{"href":"https://api.github.com/repos/openshift/library-go/pulls/146"}}},"pull_request":{"url":"https://api.github.com/repos/openshift/library-go/pulls/146","id":237414445,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM3NDE0NDQ1","html_url":"https://github.com/openshift/library-go/pull/146","diff_url":"https://github.com/openshift/library-go/pull/146.diff","patch_url":"https://github.com/openshift/library-go/pull/146.patch","issue_url":"https://api.github.com/repos/openshift/library-go/issues/146","number":146,"state":"open","locked":false,"title":"Pruning controller for static pod installer revisions","user":{"login":"damemi","id":1839101,"node_id":"MDQ6VXNlcjE4MzkxMDE=","avatar_url":"https://avatars1.githubusercontent.com/u/1839101?v=4","gravatar_id":"","url":"https://api.github.com/users/damemi","html_url":"https://github.com/damemi","followers_url":"https://api.github.com/users/damemi/followers","following_url":"https://api.github.com/users/damemi/following{/other_user}","gists_url":"https://api.github.com/users/damemi/gists{/gist_id}","starred_url":"https://api.github.com/users/damemi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/damemi/subscriptions","organizations_url":"https://api.github.com/users/damemi/orgs","repos_url":"https://api.github.com/users/damemi/repos","events_url":"https://api.github.com/users/damemi/events{/privacy}","received_events_url":"https://api.github.com/users/damemi/received_events","type":"User","site_admin":false},"body":"Follow up to https://github.com/openshift/library-go/pull/141\r\n\r\nBased off of https://github.com/openshift/library-go/pull/82\r\n\r\nCreates just the controller which interprets revision statuses and makes the call to the pruner pod","created_at":"2018-12-10T18:02:46Z","updated_at":"2018-12-11T09:04:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"03b0b523e4da42d021a94bd8f9d56db3681359db","assignee":null,"assignees":[],"requested_reviewers":[{"login":"sttts","id":730123,"node_id":"MDQ6VXNlcjczMDEyMw==","avatar_url":"https://avatars0.githubusercontent.com/u/730123?v=4","gravatar_id":"","url":"https://api.github.com/users/sttts","html_url":"https://github.com/sttts","followers_url":"https://api.github.com/users/sttts/followers","following_url":"https://api.github.com/users/sttts/following{/other_user}","gists_url":"https://api.github.com/users/sttts/gists{/gist_id}","starred_url":"https://api.github.com/users/sttts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sttts/subscriptions","organizations_url":"https://api.github.com/users/sttts/orgs","repos_url":"https://api.github.com/users/sttts/repos","events_url":"https://api.github.com/users/sttts/events{/privacy}","received_events_url":"https://api.github.com/users/sttts/received_events","type":"User","site_admin":false},{"login":"smarterclayton","id":1163175,"node_id":"MDQ6VXNlcjExNjMxNzU=","avatar_url":"https://avatars0.githubusercontent.com/u/1163175?v=4","gravatar_id":"","url":"https://api.github.com/users/smarterclayton","html_url":"https://github.com/smarterclayton","followers_url":"https://api.github.com/users/smarterclayton/followers","following_url":"https://api.github.com/users/smarterclayton/following{/other_user}","gists_url":"https://api.github.com/users/smarterclayton/gists{/gist_id}","starred_url":"https://api.github.com/users/smarterclayton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smarterclayton/subscriptions","organizations_url":"https://api.github.com/users/smarterclayton/orgs","repos_url":"https://api.github.com/users/smarterclayton/repos","events_url":"https://api.github.com/users/smarterclayton/events{/privacy}","received_events_url":"https://api.github.com/users/smarterclayton/received_events","type":"User","site_admin":false},{"login":"deads2k","id":8225098,"node_id":"MDQ6VXNlcjgyMjUwOTg=","avatar_url":"https://avatars0.githubusercontent.com/u/8225098?v=4","gravatar_id":"","url":"https://api.github.com/users/deads2k","html_url":"https://github.com/deads2k","followers_url":"https://api.github.com/users/deads2k/followers","following_url":"https://api.github.com/users/deads2k/following{/other_user}","gists_url":"https://api.github.com/users/deads2k/gists{/gist_id}","starred_url":"https://api.github.com/users/deads2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/deads2k/subscriptions","organizations_url":"https://api.github.com/users/deads2k/orgs","repos_url":"https://api.github.com/users/deads2k/repos","events_url":"https://api.github.com/users/deads2k/events{/privacy}","received_events_url":"https://api.github.com/users/deads2k/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":930108054,"node_id":"MDU6TGFiZWw5MzAxMDgwNTQ=","url":"https://api.github.com/repos/openshift/library-go/labels/size/L","name":"size/L","color":"ee9900","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/openshift/library-go/pulls/146/commits","review_comments_url":"https://api.github.com/repos/openshift/library-go/pulls/146/comments","review_comment_url":"https://api.github.com/repos/openshift/library-go/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openshift/library-go/issues/146/comments","statuses_url":"https://api.github.com/repos/openshift/library-go/statuses/9d04225504720b2e5c146d8d592c10c04dff2475","head":{"label":"damemi:staticpod-pruning-controller","ref":"staticpod-pruning-controller","sha":"9d04225504720b2e5c146d8d592c10c04dff2475","user":{"login":"damemi","id":1839101,"node_id":"MDQ6VXNlcjE4MzkxMDE=","avatar_url":"https://avatars1.githubusercontent.com/u/1839101?v=4","gravatar_id":"","url":"https://api.github.com/users/damemi","html_url":"https://github.com/damemi","followers_url":"https://api.github.com/users/damemi/followers","following_url":"https://api.github.com/users/damemi/following{/other_user}","gists_url":"https://api.github.com/users/damemi/gists{/gist_id}","starred_url":"https://api.github.com/users/damemi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/damemi/subscriptions","organizations_url":"https://api.github.com/users/damemi/orgs","repos_url":"https://api.github.com/users/damemi/repos","events_url":"https://api.github.com/users/damemi/events{/privacy}","received_events_url":"https://api.github.com/users/damemi/received_events","type":"User","site_admin":false},"repo":{"id":153466082,"node_id":"MDEwOlJlcG9zaXRvcnkxNTM0NjYwODI=","name":"library-go","full_name":"damemi/library-go","private":false,"owner":{"login":"damemi","id":1839101,"node_id":"MDQ6VXNlcjE4MzkxMDE=","avatar_url":"https://avatars1.githubusercontent.com/u/1839101?v=4","gravatar_id":"","url":"https://api.github.com/users/damemi","html_url":"https://github.com/damemi","followers_url":"https://api.github.com/users/damemi/followers","following_url":"https://api.github.com/users/damemi/following{/other_user}","gists_url":"https://api.github.com/users/damemi/gists{/gist_id}","starred_url":"https://api.github.com/users/damemi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/damemi/subscriptions","organizations_url":"https://api.github.com/users/damemi/orgs","repos_url":"https://api.github.com/users/damemi/repos","events_url":"https://api.github.com/users/damemi/events{/privacy}","received_events_url":"https://api.github.com/users/damemi/received_events","type":"User","site_admin":false},"html_url":"https://github.com/damemi/library-go","description":"Helpers for going from apis and clients to useful runtime constructs","fork":true,"url":"https://api.github.com/repos/damemi/library-go","forks_url":"https://api.github.com/repos/damemi/library-go/forks","keys_url":"https://api.github.com/repos/damemi/library-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/damemi/library-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/damemi/library-go/teams","hooks_url":"https://api.github.com/repos/damemi/library-go/hooks","issue_events_url":"https://api.github.com/repos/damemi/library-go/issues/events{/number}","events_url":"https://api.github.com/repos/damemi/library-go/events","assignees_url":"https://api.github.com/repos/damemi/library-go/assignees{/user}","branches_url":"https://api.github.com/repos/damemi/library-go/branches{/branch}","tags_url":"https://api.github.com/repos/damemi/library-go/tags","blobs_url":"https://api.github.com/repos/damemi/library-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/damemi/library-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/damemi/library-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/damemi/library-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/damemi/library-go/statuses/{sha}","languages_url":"https://api.github.com/repos/damemi/library-go/languages","stargazers_url":"https://api.github.com/repos/damemi/library-go/stargazers","contributors_url":"https://api.github.com/repos/damemi/library-go/contributors","subscribers_url":"https://api.github.com/repos/damemi/library-go/subscribers","subscription_url":"https://api.github.com/repos/damemi/library-go/subscription","commits_url":"https://api.github.com/repos/damemi/library-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/damemi/library-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/damemi/library-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/damemi/library-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/damemi/library-go/contents/{+path}","compare_url":"https://api.github.com/repos/damemi/library-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/damemi/library-go/merges","archive_url":"https://api.github.com/repos/damemi/library-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/damemi/library-go/downloads","issues_url":"https://api.github.com/repos/damemi/library-go/issues{/number}","pulls_url":"https://api.github.com/repos/damemi/library-go/pulls{/number}","milestones_url":"https://api.github.com/repos/damemi/library-go/milestones{/number}","notifications_url":"https://api.github.com/repos/damemi/library-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/damemi/library-go/labels{/name}","releases_url":"https://api.github.com/repos/damemi/library-go/releases{/id}","deployments_url":"https://api.github.com/repos/damemi/library-go/deployments","created_at":"2018-10-17T13:56:45Z","updated_at":"2018-11-16T18:40:11Z","pushed_at":"2018-12-10T21:04:10Z","git_url":"git://github.com/damemi/library-go.git","ssh_url":"git@github.com:damemi/library-go.git","clone_url":"https://github.com/damemi/library-go.git","svn_url":"https://github.com/damemi/library-go","homepage":null,"size":20680,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"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":0,"default_branch":"master"}},"base":{"label":"openshift:master","ref":"master","sha":"f7ae9d85accb03d7a7002615c67848838b2c381c","user":{"login":"openshift","id":792337,"node_id":"MDEyOk9yZ2FuaXphdGlvbjc5MjMzNw==","avatar_url":"https://avatars3.githubusercontent.com/u/792337?v=4","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"repo":{"id":132917906,"node_id":"MDEwOlJlcG9zaXRvcnkxMzI5MTc5MDY=","name":"library-go","full_name":"openshift/library-go","private":false,"owner":{"login":"openshift","id":792337,"node_id":"MDEyOk9yZ2FuaXphdGlvbjc5MjMzNw==","avatar_url":"https://avatars3.githubusercontent.com/u/792337?v=4","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/openshift/library-go","description":"Helpers for going from apis and clients to useful runtime constructs","fork":false,"url":"https://api.github.com/repos/openshift/library-go","forks_url":"https://api.github.com/repos/openshift/library-go/forks","keys_url":"https://api.github.com/repos/openshift/library-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openshift/library-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openshift/library-go/teams","hooks_url":"https://api.github.com/repos/openshift/library-go/hooks","issue_events_url":"https://api.github.com/repos/openshift/library-go/issues/events{/number}","events_url":"https://api.github.com/repos/openshift/library-go/events","assignees_url":"https://api.github.com/repos/openshift/library-go/assignees{/user}","branches_url":"https://api.github.com/repos/openshift/library-go/branches{/branch}","tags_url":"https://api.github.com/repos/openshift/library-go/tags","blobs_url":"https://api.github.com/repos/openshift/library-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openshift/library-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openshift/library-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/openshift/library-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openshift/library-go/statuses/{sha}","languages_url":"https://api.github.com/repos/openshift/library-go/languages","stargazers_url":"https://api.github.com/repos/openshift/library-go/stargazers","contributors_url":"https://api.github.com/repos/openshift/library-go/contributors","subscribers_url":"https://api.github.com/repos/openshift/library-go/subscribers","subscription_url":"https://api.github.com/repos/openshift/library-go/subscription","commits_url":"https://api.github.com/repos/openshift/library-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/openshift/library-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/openshift/library-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/openshift/library-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/openshift/library-go/contents/{+path}","compare_url":"https://api.github.com/repos/openshift/library-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openshift/library-go/merges","archive_url":"https://api.github.com/repos/openshift/library-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openshift/library-go/downloads","issues_url":"https://api.github.com/repos/openshift/library-go/issues{/number}","pulls_url":"https://api.github.com/repos/openshift/library-go/pulls{/number}","milestones_url":"https://api.github.com/repos/openshift/library-go/milestones{/number}","notifications_url":"https://api.github.com/repos/openshift/library-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openshift/library-go/labels{/name}","releases_url":"https://api.github.com/repos/openshift/library-go/releases{/id}","deployments_url":"https://api.github.com/repos/openshift/library-go/deployments","created_at":"2018-05-10T15:14:38Z","updated_at":"2018-12-09T15:24:55Z","pushed_at":"2018-12-10T21:04:11Z","git_url":"git://github.com/openshift/library-go.git","ssh_url":"git@github.com:openshift/library-go.git","clone_url":"https://github.com/openshift/library-go.git","svn_url":"https://github.com/openshift/library-go","homepage":null,"size":20666,"stargazers_count":8,"watchers_count":8,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":18,"mirror_url":null,"archived":false,"open_issues_count":12,"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":18,"open_issues":12,"watchers":8,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openshift/library-go/pulls/146"},"html":{"href":"https://github.com/openshift/library-go/pull/146"},"issue":{"href":"https://api.github.com/repos/openshift/library-go/issues/146"},"comments":{"href":"https://api.github.com/repos/openshift/library-go/issues/146/comments"},"review_comments":{"href":"https://api.github.com/repos/openshift/library-go/pulls/146/comments"},"review_comment":{"href":"https://api.github.com/repos/openshift/library-go/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openshift/library-go/pulls/146/commits"},"statuses":{"href":"https://api.github.com/repos/openshift/library-go/statuses/9d04225504720b2e5c146d8d592c10c04dff2475"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"mfojtik"}}