{"action":"created","comment":{"url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/comments/210650660","pull_request_review_id":146911158,"id":210650660,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMDY1MDY2MA==","diff_hunk":"@@ -0,0 +1,295 @@\n+// Copyright © 2016-2018 Genome Research Limited\n+// Author: Theo Barber-Bany <tb15@sanger.ac.uk>.\n+//\n+//  This file is part of wr.\n+//\n+//  wr is free software: you can redistribute it and/or modify\n+//  it under the terms of the GNU Lesser General Public License as published by\n+//  the Free Software Foundation, either version 3 of the License, or\n+//  (at your option) any later version.\n+//\n+//  wr is distributed in the hope that it will be useful,\n+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+//  GNU Lesser General Public License for more details.\n+//\n+//  You should have received a copy of the GNU Lesser General Public License\n+//  along with wr. If not, see <http://www.gnu.org/licenses/>.\n+\n+package deployment\n+\n+/*\n+Package deployment a kubernetes controller to oversee the deployment\n+of the wr scheduler controller into a kubernetes cluster. It handles\n+copying configuration files and binaries as well as port forwarding.\n+*/\n+\n+import (\n+\t\"encoding/gob\"\n+\t\"fmt\"\n+\t\"os\"\n+\t\"time\"\n+\n+\t\"github.com/VertebrateResequencing/wr/cloud\"\n+\t\"github.com/VertebrateResequencing/wr/kubernetes/client\"\n+\t\"github.com/inconshreveable/log15\"\n+\tapiv1 \"k8s.io/api/core/v1\"\n+\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n+\t\"k8s.io/apimachinery/pkg/runtime\"\n+\tutilruntime \"k8s.io/apimachinery/pkg/util/runtime\"\n+\t\"k8s.io/apimachinery/pkg/util/wait\"\n+\t\"k8s.io/apimachinery/pkg/watch\"\n+\t\"k8s.io/client-go/kubernetes\"\n+\t\"k8s.io/client-go/rest\"\n+\t\"k8s.io/client-go/tools/cache\"\n+\t\"k8s.io/client-go/util/workqueue\"\n+)\n+\n+const maxRetries = 5\n+\n+// Controller defines a deployment controller\n+// and it's options\n+type Controller struct {\n+\tClient     *client.Kubernetesp\n+\tClientset  kubernetes.Interface\n+\tRestconfig *rest.Config\n+\tOpts       *DeployOpts\n+\tqueue      workqueue.RateLimitingInterface\n+\tinformer   cache.SharedIndexInformer\n+}\n+\n+// DeployOpts specify the options for the deployment\n+type DeployOpts struct {\n+\tContainerImage  string             // docker hub image\n+\tTempMountPath   string             // where to mount the binary\n+\tFiles           []client.FilePair  // Files to tar across\n+\tBinaryPath      string             // full path to the binary to be executed\n+\tBinaryArgs      []string           // arguments to the binary\n+\tConfigMapName   string             // name of the configmap to execute\n+\tConfigMountPath string             // path to the configmap\n+\tRequiredPorts   []int              // ports that require forwarding\n+\tAttachCmdOpts   *client.CmdOptions // relevant options for the attachCmd\n+\tResourcePath    string             // Path to the resource file kubeCmd creates\n+\tLogger          log15.Logger\n+}\n+\n+func (c *Controller) createQueueAndInformer() {\n+\tc.queue = workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())\n+\n+\tc.informer = cache.NewSharedIndexInformer(\n+\t\t&cache.ListWatch{\n+\t\t\tListFunc: func(options metav1.ListOptions) (runtime.Object, error) {\n+\t\t\t\treturn c.Clientset.CoreV1().Pods(c.Client.NewNamespaceName).List(metav1.ListOptions{\n+\t\t\t\t\tLabelSelector: \"app=wr-manager\",\n+\t\t\t\t})\n+\n+\t\t\t},\n+\t\t\tWatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {\n+\t\t\t\treturn c.Clientset.CoreV1().Pods(c.Client.NewNamespaceName).Watch(metav1.ListOptions{\n+\t\t\t\t\tLabelSelector:        \"app=wr-manager\",\n+\t\t\t\t\tIncludeUninitialized: true,\n+\t\t\t\t\tWatch:                true,\n+\t\t\t\t})\n+\t\t\t},\n+\t\t},\n+\t\t&apiv1.Pod{},\n+\t\t0, //Skip resync\n+\t\tcache.Indexers{},\n+\t)\n+}\n+\n+func (c *Controller) addEventHandlers() {\n+\tc.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n+\t\tAddFunc: func(obj interface{}) {\n+\t\t\tkey, err := cache.MetaNamespaceKeyFunc(obj)\n+\t\t\tif err == nil {\n+\t\t\t\tc.queue.Add(key)\n+\t\t\t}\n+\t\t},\n+\t\tUpdateFunc: func(oldObj, newObj interface{}) {\n+\t\t\tkey, err := cache.MetaNamespaceKeyFunc(newObj)\n+\t\t\tif err == nil {\n+\t\t\t\tc.queue.Add(key)\n+\t\t\t}\n+\n+\t\t},\n+\t\tDeleteFunc: func(obj interface{}) {\n+\t\t\tkey, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)\n+\t\t\tif err == nil {\n+\t\t\t\tc.queue.Add(key)\n+\t\t\t}\n+\t\t},\n+\t})\n+}\n+\n+// HasSynced is required for cache.Controller interface.\n+func (c *Controller) HasSynced() bool {\n+\treturn c.informer.HasSynced()\n+}\n+\n+// Run starts SharedInformer watching for pods, and sends their keys to workqueue\n+// StopCh used to send interrupt\n+func (c *Controller) Run(stopCh <-chan struct{}) {\n+\tc.createQueueAndInformer()\n+\tc.addEventHandlers()\n+\t// don't let panics crash the process\n+\tdefer utilruntime.HandleCrash()\n+\t// Ensure workqueue is shut down properly\n+\tdefer c.queue.ShutDown()\n+\n+\tgo c.informer.Run(stopCh)\n+\n+\tif !cache.WaitForCacheSync(stopCh, c.HasSynced) {\n+\t\tutilruntime.HandleError(fmt.Errorf(\"Timed out waiting for caches to sync\"))\n+\t\treturn\n+\t}\n+\n+\t// runWorker loops until 'bad thing'. '.Until' will\n+\t// restart the worker after a second\n+\twait.Until(c.runWorker, time.Second, stopCh)\n+}\n+\n+func (c *Controller) runWorker() {\n+\t// processNextWorkItem automatically waits for work\n+\tfor c.processNextItem() {\n+\t\t// loop\n+\t}\n+}\n+\n+func (c *Controller) processNextItem() bool {\n+\t// pull next key from queue.\n+\t// look up key in cache\n+\tkey, quit := c.queue.Get()\n+\tif quit {\n+\t\treturn false\n+\t}\n+\n+\t// Indicate to queue key has been processed\n+\tdefer c.queue.Done(key)\n+\n+\t// do processing on key\n+\terr := c.processItem(key.(string))\n+\n+\tif err == nil {\n+\t\t// No error => queue stop tracking history\n+\t\tc.queue.Forget(key)\n+\t} else if c.queue.NumRequeues(key) < maxRetries {\n+\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Error processing %s, will retry: %v\\n\", key, err))\n+\t\t// requeue\n+\t\tc.queue.AddRateLimited(key)\n+\t} else {\n+\t\t// err != nil and too many retries\n+\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Error processing %s, giving up: %v\\n\", key, err))\n+\t\tc.queue.Forget(key)\n+\t\tutilruntime.HandleError(err)\n+\t}\n+\n+\treturn true\n+}\n+\n+// processItem(key) is where we define how to react to an item coming\n+// off the work queue\n+func (c *Controller) processItem(key string) error {\n+\tc.Opts.Logger.Debug(fmt.Sprintf(\"Processing change to Pod %s\", key))\n+\n+\tobj, exists, err := c.informer.GetIndexer().GetByKey(key)\n+\tif err != nil {\n+\t\treturn fmt.Errorf(\"Error fetching object with key %s from store: %v\", key, err)\n+\t}\n+\n+\tif !exists {\n+\t\tc.Opts.Logger.Debug(fmt.Sprintf(\"Object with key %s deleted. \\n\\nObj: %v\", key, obj))\n+\t\tfmt.Printf(\"\\n\\n\")\n+\t\tfmt.Println(\"====================\")\n+\t\tfmt.Printf(\"\\n\\n\")\n+\t\treturn nil\n+\t}\n+\terr = c.processObj(obj)\n+\t//jsonObj, err := json.Marshal(obj)\n+\t//fmt.Printf(string(jsonObj))\n+\t//fmt.Printf(\"Object with key %s created. \\n\\nObj: %v\", key, obj)\n+\tfmt.Printf(\"\\n\\n\")\n+\tfmt.Println(\"====================\")\n+\tfmt.Printf(\"\\n\\n\")\n+\treturn err\n+}\n+\n+// Process a generic object\n+func (c *Controller) processObj(obj interface{}) error {\n+\tfmt.Println(\"processObj called\")\n+\tfmt.Printf(\"Object has type %T\\n\", obj)\n+\tswitch v := obj.(type) {\n+\tcase *apiv1.Pod:\n+\t\tfmt.Println(\"Case pod. Calling processPod\")\n+\t\tc.processPod(v)\n+\tdefault:\n+\t\tfmt.Println(\"Default case executed, throwing error\")\n+\t\treturn error(fmt.Errorf(\"obj is not a pod\"))\n+\t}\n+\treturn nil\n+}\n+\n+// processPod defines how to react to a pod coming off the workqueue\n+// in an observed state.\n+// Assumes there is only 1 initcontainer\n+func (c *Controller) processPod(obj *apiv1.Pod) {\n+\tfmt.Println(\"processPod Called\")\n+\tif len(obj.Status.InitContainerStatuses) != 0 {\n+\t\tswitch {\n+\t\tcase obj.Status.InitContainerStatuses[0].State.Waiting != nil:\n+\t\t\tc.Opts.Logger.Debug(fmt.Sprintf(\"InitContainer Waiting!\"))\n+\n+\t\tcase obj.Status.InitContainerStatuses[0].State.Running != nil:\n+\t\t\tc.Opts.Logger.Debug(fmt.Sprintf(\"InitContainer Running!\"))\n+\t\t\tc.Opts.Logger.Info(fmt.Sprintf(\"Calling CopyTar with files: %+v\", c.Opts.Files))\n+\t\t\terr := c.Client.CopyTar(c.Opts.Files, obj)\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Error copying tarball: %s\", err))\n+\t\t\t}\n+\t\tcase obj.Status.ContainerStatuses[0].State.Running != nil:\n+\t\t\t// Write the pod name, name to the resources file.\n+\t\t\t// This allows us to retrieve it to obtain the client.token\n+\t\t\tresources := &cloud.Resources{}\n+\t\t\tfile, err := os.OpenFile(c.Opts.ResourcePath, os.O_RDONLY, 0600)\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Could not open resource file with path: %s\", err))\n+\t\t\t}\n+\t\t\tc.Opts.Logger.Info(fmt.Sprintf(\"Opened resource file with path %s\", c.Opts.ResourcePath))\n+\t\t\tdecoder := gob.NewDecoder(file)\n+\t\t\terr = decoder.Decode(resources)\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Error decoding resource file: %s\", err))\n+\t\t\t}\n+\t\t\terr = file.Close()\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Failed to close resource file: %s\", err))\n+\t\t\t}\n+\t\t\tfile2, err := os.OpenFile(c.Opts.ResourcePath, os.O_WRONLY, 0600)\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Failed to open file2 %s\", err))\n+\t\t\t}\n+\t\t\tresources.Details[\"manager-pod\"] = obj.ObjectMeta.Name\n+\t\t\tencoder := gob.NewEncoder(file2)\n+\t\t\terr = encoder.Encode(resources)\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Failed to encode resource file: %s\", err))\n+\t\t\t}\n+\t\t\terr = file2.Close()\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Failed to close resource file2: %s\", err))\n+\t\t\t}\n+\n+\t\t\tif err != nil {\n+\t\t\t\tc.Opts.Logger.Error(fmt.Sprintf(\"Failed to close resource file %s\", err))\n+\t\t\t}\n+\t\t\tc.Opts.Logger.Info(fmt.Sprintf(\"Stored manager pod name %s in resource file\", obj.ObjectMeta.Name))\n+\t\t\tc.Opts.Logger.Info(fmt.Sprintf(\"WR manager container is running, calling PortForward with ports %v\", c.Opts.RequiredPorts))\n+\t\t\tgo c.Client.PortForward(obj, c.Opts.RequiredPorts)\n+\t\tdefault:\n+\t\t\tc.Opts.Logger.Debug(fmt.Sprintf(\"Not InitContainer or WR Manager container related\"))\n+\t\t}\n+\t} else {\n+\t\tc.Opts.Logger.Debug(fmt.Sprintf(\"InitContainerStatuses not initialised yet\"))\n+\t}\n+\treturn","path":"kubernetes/deployment/controller.go","position":294,"original_position":294,"commit_id":"d4040253a2a4cc1e2e5d7bb651f68c79ecc9e90e","original_commit_id":"d4040253a2a4cc1e2e5d7bb651f68c79ecc9e90e","user":{"login":"golangci","id":35628013,"node_id":"MDQ6VXNlcjM1NjI4MDEz","avatar_url":"https://avatars3.githubusercontent.com/u/35628013?v=4","gravatar_id":"","url":"https://api.github.com/users/golangci","html_url":"https://github.com/golangci","followers_url":"https://api.github.com/users/golangci/followers","following_url":"https://api.github.com/users/golangci/following{/other_user}","gists_url":"https://api.github.com/users/golangci/gists{/gist_id}","starred_url":"https://api.github.com/users/golangci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/golangci/subscriptions","organizations_url":"https://api.github.com/users/golangci/orgs","repos_url":"https://api.github.com/users/golangci/repos","events_url":"https://api.github.com/users/golangci/events{/privacy}","received_events_url":"https://api.github.com/users/golangci/received_events","type":"User","site_admin":false},"body":"redundant return statement","created_at":"2018-08-16T15:55:10Z","updated_at":"2018-08-16T15:55:11Z","html_url":"https://github.com/VertebrateResequencing/wr/pull/132#discussion_r210650660","pull_request_url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/comments/210650660"},"html":{"href":"https://github.com/VertebrateResequencing/wr/pull/132#discussion_r210650660"},"pull_request":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132"}}},"pull_request":{"url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132","id":208906282,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA4OTA2Mjgy","html_url":"https://github.com/VertebrateResequencing/wr/pull/132","diff_url":"https://github.com/VertebrateResequencing/wr/pull/132.diff","patch_url":"https://github.com/VertebrateResequencing/wr/pull/132.patch","issue_url":"https://api.github.com/repos/VertebrateResequencing/wr/issues/132","number":132,"state":"closed","locked":false,"title":"Add Kubernetes support","user":{"login":"theobarberbany","id":10214743,"node_id":"MDQ6VXNlcjEwMjE0NzQz","avatar_url":"https://avatars3.githubusercontent.com/u/10214743?v=4","gravatar_id":"","url":"https://api.github.com/users/theobarberbany","html_url":"https://github.com/theobarberbany","followers_url":"https://api.github.com/users/theobarberbany/followers","following_url":"https://api.github.com/users/theobarberbany/following{/other_user}","gists_url":"https://api.github.com/users/theobarberbany/gists{/gist_id}","starred_url":"https://api.github.com/users/theobarberbany/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theobarberbany/subscriptions","organizations_url":"https://api.github.com/users/theobarberbany/orgs","repos_url":"https://api.github.com/users/theobarberbany/repos","events_url":"https://api.github.com/users/theobarberbany/events{/privacy}","received_events_url":"https://api.github.com/users/theobarberbany/received_events","type":"User","site_admin":false},"body":"Adds support to use a Kubernetes cluster as underlying cloud infrastructure.\r\nAdds ability to specify `--reserve_timeout` to a `wr add` command. \r\nAdds end to end testing in CI.\r\nMoves from glyde to go dep for dependency management. ","created_at":"2018-08-16T15:53:52Z","updated_at":"2018-08-16T15:55:10Z","closed_at":"2018-08-16T15:54:38Z","merged_at":null,"merge_commit_sha":"5687001c2c299e5cd0c01f1be63e33df19e54f4a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132/commits","review_comments_url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132/comments","review_comment_url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/comments{/number}","comments_url":"https://api.github.com/repos/VertebrateResequencing/wr/issues/132/comments","statuses_url":"https://api.github.com/repos/VertebrateResequencing/wr/statuses/d4040253a2a4cc1e2e5d7bb651f68c79ecc9e90e","head":{"label":"theobarberbany:test","ref":"test","sha":"d4040253a2a4cc1e2e5d7bb651f68c79ecc9e90e","user":{"login":"theobarberbany","id":10214743,"node_id":"MDQ6VXNlcjEwMjE0NzQz","avatar_url":"https://avatars3.githubusercontent.com/u/10214743?v=4","gravatar_id":"","url":"https://api.github.com/users/theobarberbany","html_url":"https://github.com/theobarberbany","followers_url":"https://api.github.com/users/theobarberbany/followers","following_url":"https://api.github.com/users/theobarberbany/following{/other_user}","gists_url":"https://api.github.com/users/theobarberbany/gists{/gist_id}","starred_url":"https://api.github.com/users/theobarberbany/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theobarberbany/subscriptions","organizations_url":"https://api.github.com/users/theobarberbany/orgs","repos_url":"https://api.github.com/users/theobarberbany/repos","events_url":"https://api.github.com/users/theobarberbany/events{/privacy}","received_events_url":"https://api.github.com/users/theobarberbany/received_events","type":"User","site_admin":false},"repo":{"id":125854677,"node_id":"MDEwOlJlcG9zaXRvcnkxMjU4NTQ2Nzc=","name":"wr","full_name":"theobarberbany/wr","owner":{"login":"theobarberbany","id":10214743,"node_id":"MDQ6VXNlcjEwMjE0NzQz","avatar_url":"https://avatars3.githubusercontent.com/u/10214743?v=4","gravatar_id":"","url":"https://api.github.com/users/theobarberbany","html_url":"https://github.com/theobarberbany","followers_url":"https://api.github.com/users/theobarberbany/followers","following_url":"https://api.github.com/users/theobarberbany/following{/other_user}","gists_url":"https://api.github.com/users/theobarberbany/gists{/gist_id}","starred_url":"https://api.github.com/users/theobarberbany/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theobarberbany/subscriptions","organizations_url":"https://api.github.com/users/theobarberbany/orgs","repos_url":"https://api.github.com/users/theobarberbany/repos","events_url":"https://api.github.com/users/theobarberbany/events{/privacy}","received_events_url":"https://api.github.com/users/theobarberbany/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/theobarberbany/wr","description":"High performance Workflow Runner","fork":true,"url":"https://api.github.com/repos/theobarberbany/wr","forks_url":"https://api.github.com/repos/theobarberbany/wr/forks","keys_url":"https://api.github.com/repos/theobarberbany/wr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/theobarberbany/wr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/theobarberbany/wr/teams","hooks_url":"https://api.github.com/repos/theobarberbany/wr/hooks","issue_events_url":"https://api.github.com/repos/theobarberbany/wr/issues/events{/number}","events_url":"https://api.github.com/repos/theobarberbany/wr/events","assignees_url":"https://api.github.com/repos/theobarberbany/wr/assignees{/user}","branches_url":"https://api.github.com/repos/theobarberbany/wr/branches{/branch}","tags_url":"https://api.github.com/repos/theobarberbany/wr/tags","blobs_url":"https://api.github.com/repos/theobarberbany/wr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/theobarberbany/wr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/theobarberbany/wr/git/refs{/sha}","trees_url":"https://api.github.com/repos/theobarberbany/wr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/theobarberbany/wr/statuses/{sha}","languages_url":"https://api.github.com/repos/theobarberbany/wr/languages","stargazers_url":"https://api.github.com/repos/theobarberbany/wr/stargazers","contributors_url":"https://api.github.com/repos/theobarberbany/wr/contributors","subscribers_url":"https://api.github.com/repos/theobarberbany/wr/subscribers","subscription_url":"https://api.github.com/repos/theobarberbany/wr/subscription","commits_url":"https://api.github.com/repos/theobarberbany/wr/commits{/sha}","git_commits_url":"https://api.github.com/repos/theobarberbany/wr/git/commits{/sha}","comments_url":"https://api.github.com/repos/theobarberbany/wr/comments{/number}","issue_comment_url":"https://api.github.com/repos/theobarberbany/wr/issues/comments{/number}","contents_url":"https://api.github.com/repos/theobarberbany/wr/contents/{+path}","compare_url":"https://api.github.com/repos/theobarberbany/wr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/theobarberbany/wr/merges","archive_url":"https://api.github.com/repos/theobarberbany/wr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/theobarberbany/wr/downloads","issues_url":"https://api.github.com/repos/theobarberbany/wr/issues{/number}","pulls_url":"https://api.github.com/repos/theobarberbany/wr/pulls{/number}","milestones_url":"https://api.github.com/repos/theobarberbany/wr/milestones{/number}","notifications_url":"https://api.github.com/repos/theobarberbany/wr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/theobarberbany/wr/labels{/name}","releases_url":"https://api.github.com/repos/theobarberbany/wr/releases{/id}","deployments_url":"https://api.github.com/repos/theobarberbany/wr/deployments","created_at":"2018-03-19T12:33:26Z","updated_at":"2018-03-19T12:33:28Z","pushed_at":"2018-08-16T15:46:38Z","git_url":"git://github.com/theobarberbany/wr.git","ssh_url":"git@github.com:theobarberbany/wr.git","clone_url":"https://github.com/theobarberbany/wr.git","svn_url":"https://github.com/theobarberbany/wr","homepage":"","size":26478,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"VertebrateResequencing:master","ref":"master","sha":"379310883c8c5e0dc2a3b535f8c99ae39bba6bf8","user":{"login":"VertebrateResequencing","id":506811,"node_id":"MDEyOk9yZ2FuaXphdGlvbjUwNjgxMQ==","avatar_url":"https://avatars2.githubusercontent.com/u/506811?v=4","gravatar_id":"","url":"https://api.github.com/users/VertebrateResequencing","html_url":"https://github.com/VertebrateResequencing","followers_url":"https://api.github.com/users/VertebrateResequencing/followers","following_url":"https://api.github.com/users/VertebrateResequencing/following{/other_user}","gists_url":"https://api.github.com/users/VertebrateResequencing/gists{/gist_id}","starred_url":"https://api.github.com/users/VertebrateResequencing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/VertebrateResequencing/subscriptions","organizations_url":"https://api.github.com/users/VertebrateResequencing/orgs","repos_url":"https://api.github.com/users/VertebrateResequencing/repos","events_url":"https://api.github.com/users/VertebrateResequencing/events{/privacy}","received_events_url":"https://api.github.com/users/VertebrateResequencing/received_events","type":"Organization","site_admin":false},"repo":{"id":10549212,"node_id":"MDEwOlJlcG9zaXRvcnkxMDU0OTIxMg==","name":"wr","full_name":"VertebrateResequencing/wr","owner":{"login":"VertebrateResequencing","id":506811,"node_id":"MDEyOk9yZ2FuaXphdGlvbjUwNjgxMQ==","avatar_url":"https://avatars2.githubusercontent.com/u/506811?v=4","gravatar_id":"","url":"https://api.github.com/users/VertebrateResequencing","html_url":"https://github.com/VertebrateResequencing","followers_url":"https://api.github.com/users/VertebrateResequencing/followers","following_url":"https://api.github.com/users/VertebrateResequencing/following{/other_user}","gists_url":"https://api.github.com/users/VertebrateResequencing/gists{/gist_id}","starred_url":"https://api.github.com/users/VertebrateResequencing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/VertebrateResequencing/subscriptions","organizations_url":"https://api.github.com/users/VertebrateResequencing/orgs","repos_url":"https://api.github.com/users/VertebrateResequencing/repos","events_url":"https://api.github.com/users/VertebrateResequencing/events{/privacy}","received_events_url":"https://api.github.com/users/VertebrateResequencing/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/VertebrateResequencing/wr","description":"High performance Workflow Runner","fork":false,"url":"https://api.github.com/repos/VertebrateResequencing/wr","forks_url":"https://api.github.com/repos/VertebrateResequencing/wr/forks","keys_url":"https://api.github.com/repos/VertebrateResequencing/wr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/VertebrateResequencing/wr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/VertebrateResequencing/wr/teams","hooks_url":"https://api.github.com/repos/VertebrateResequencing/wr/hooks","issue_events_url":"https://api.github.com/repos/VertebrateResequencing/wr/issues/events{/number}","events_url":"https://api.github.com/repos/VertebrateResequencing/wr/events","assignees_url":"https://api.github.com/repos/VertebrateResequencing/wr/assignees{/user}","branches_url":"https://api.github.com/repos/VertebrateResequencing/wr/branches{/branch}","tags_url":"https://api.github.com/repos/VertebrateResequencing/wr/tags","blobs_url":"https://api.github.com/repos/VertebrateResequencing/wr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/VertebrateResequencing/wr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/VertebrateResequencing/wr/git/refs{/sha}","trees_url":"https://api.github.com/repos/VertebrateResequencing/wr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/VertebrateResequencing/wr/statuses/{sha}","languages_url":"https://api.github.com/repos/VertebrateResequencing/wr/languages","stargazers_url":"https://api.github.com/repos/VertebrateResequencing/wr/stargazers","contributors_url":"https://api.github.com/repos/VertebrateResequencing/wr/contributors","subscribers_url":"https://api.github.com/repos/VertebrateResequencing/wr/subscribers","subscription_url":"https://api.github.com/repos/VertebrateResequencing/wr/subscription","commits_url":"https://api.github.com/repos/VertebrateResequencing/wr/commits{/sha}","git_commits_url":"https://api.github.com/repos/VertebrateResequencing/wr/git/commits{/sha}","comments_url":"https://api.github.com/repos/VertebrateResequencing/wr/comments{/number}","issue_comment_url":"https://api.github.com/repos/VertebrateResequencing/wr/issues/comments{/number}","contents_url":"https://api.github.com/repos/VertebrateResequencing/wr/contents/{+path}","compare_url":"https://api.github.com/repos/VertebrateResequencing/wr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/VertebrateResequencing/wr/merges","archive_url":"https://api.github.com/repos/VertebrateResequencing/wr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/VertebrateResequencing/wr/downloads","issues_url":"https://api.github.com/repos/VertebrateResequencing/wr/issues{/number}","pulls_url":"https://api.github.com/repos/VertebrateResequencing/wr/pulls{/number}","milestones_url":"https://api.github.com/repos/VertebrateResequencing/wr/milestones{/number}","notifications_url":"https://api.github.com/repos/VertebrateResequencing/wr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/VertebrateResequencing/wr/labels{/name}","releases_url":"https://api.github.com/repos/VertebrateResequencing/wr/releases{/id}","deployments_url":"https://api.github.com/repos/VertebrateResequencing/wr/deployments","created_at":"2013-06-07T12:16:02Z","updated_at":"2018-08-07T09:38:30Z","pushed_at":"2018-08-16T15:53:53Z","git_url":"git://github.com/VertebrateResequencing/wr.git","ssh_url":"git@github.com:VertebrateResequencing/wr.git","clone_url":"https://github.com/VertebrateResequencing/wr.git","svn_url":"https://github.com/VertebrateResequencing/wr","homepage":"","size":2918,"stargazers_count":11,"watchers_count":11,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"archived":false,"open_issues_count":33,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":11,"open_issues":33,"watchers":11,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132"},"html":{"href":"https://github.com/VertebrateResequencing/wr/pull/132"},"issue":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/issues/132"},"comments":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/issues/132/comments"},"review_comments":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132/comments"},"review_comment":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/pulls/132/commits"},"statuses":{"href":"https://api.github.com/repos/VertebrateResequencing/wr/statuses/d4040253a2a4cc1e2e5d7bb651f68c79ecc9e90e"}},"author_association":"NONE"}}
{"actor":{"display_login":"golangci"}}