{"action":"created","comment":{"url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/comments/236545709","pull_request_review_id":178639273,"id":236545709,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzNjU0NTcwOQ==","diff_hunk":"@@ -0,0 +1,204 @@\n+package openshift\n+\n+import (\n+\t\"fmt\"\n+\t\"github.com/fabric8-services/fabric8-common/log\"\n+\t\"github.com/fabric8-services/fabric8-tenant/environment\"\n+\t\"gopkg.in/yaml.v2\"\n+)\n+\n+// ObjectEndpoints is list of MethodDefinitions for a particular object endpoint (eg. `/oapi/v1/projectrequests`).\n+// In other words, is saying which methods (Post/Delete/Get/Patch) are allowed to be performed for the endpoint\n+type ObjectEndpoints struct {\n+\tMethods map[string]*MethodDefinition\n+}\n+\n+var (\n+\tAllObjectEndpoints = map[string]*ObjectEndpoints{\n+\t\tenvironment.ValKindNamespace: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces`, POST(IgnoreConflicts, GetObject)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindProject: endpoints(\n+\t\t\tendpoint(`/oapi/v1/projects`, POST(WhenConflictThenDeleteAndRedo, GetObject)),\n+\t\t\tendpoint(`/oapi/v1/projects/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindProjectRequest: endpoints(\n+\t\t\tendpoint(`/oapi/v1/projectrequests`, POST(IgnoreConflicts, GetObject)),\n+\t\t\tendpoint(`/oapi/v1/projects/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindRole: endpoints(\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/roles`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/roles/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindRoleBinding: endpoints(\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/rolebindings`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/rolebindings/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindRoleBindingRestriction: endpoints(\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/rolebindingrestrictions`, POST(WhenConflictThenDeleteAndRedo).WithModifier(NeedMasterToken)),\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/rolebindingrestrictions/{{ index . \"metadata\" \"name\"}}`,\n+\t\t\t\tPATCH().WithModifier(NeedMasterToken), GET().WithModifier(NeedMasterToken), DELETE().WithModifier(NeedMasterToken))),\n+\n+\t\tenvironment.ValKindRoute: endpoints(\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/routes`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/oapi/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/routes/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindDeployment: endpoints(\n+\t\t\tendpoint(`/apis/extensions/v1beta1/namespaces/{{ index . \"metadata\" \"namespace\"}}/deployments`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/apis/extensions/v1beta1/namespaces/{{ index . \"metadata\" \"namespace\"}}/deployments/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindDeploymentConfig: endpoints(\n+\t\t\tendpoint(`/apis/apps.openshift.io/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/deploymentconfigs`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/apis/apps.openshift.io/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/deploymentconfigs/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindPersistenceVolumeClaim: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/persistentvolumeclaims`, POST(IgnoreConflicts)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/persistentvolumeclaims/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindService: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/services`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/services/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindSecret: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/secrets`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/secrets/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindServiceAccount: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/serviceaccounts`, POST(IgnoreConflicts)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/serviceaccounts/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindConfigMap: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/configmaps`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/configmaps/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindResourceQuota: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/resourcequotas`, POST(WhenConflictThenDeleteAndRedo, GetObject)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/resourcequotas/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindLimitRange: endpoints(\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/limitranges`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/api/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/limitranges/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\n+\t\tenvironment.ValKindJob: endpoints(\n+\t\t\tendpoint(`/apis/batch/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/jobs`, POST(WhenConflictThenDeleteAndRedo)),\n+\t\t\tendpoint(`/apis/batch/v1/namespaces/{{ index . \"metadata\" \"namespace\"}}/jobs/{{ index . \"metadata\" \"name\"}}`, PATCH(), GET(), DELETE())),\n+\t}","path":"openshift/endpoints.go","position":86,"original_position":86,"commit_id":"a07dd9cf79f92ce20dd136a0f95c74ffdfaf0a40","original_commit_id":"505618a7f2654a553f8d56d60868ef37d1f27046","user":{"login":"MatousJobanek","id":1510709,"node_id":"MDQ6VXNlcjE1MTA3MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1510709?v=4","gravatar_id":"","url":"https://api.github.com/users/MatousJobanek","html_url":"https://github.com/MatousJobanek","followers_url":"https://api.github.com/users/MatousJobanek/followers","following_url":"https://api.github.com/users/MatousJobanek/following{/other_user}","gists_url":"https://api.github.com/users/MatousJobanek/gists{/gist_id}","starred_url":"https://api.github.com/users/MatousJobanek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MatousJobanek/subscriptions","organizations_url":"https://api.github.com/users/MatousJobanek/orgs","repos_url":"https://api.github.com/users/MatousJobanek/repos","events_url":"https://api.github.com/users/MatousJobanek/events{/privacy}","received_events_url":"https://api.github.com/users/MatousJobanek/received_events","type":"User","site_admin":false},"body":"@nurali-techie thank you very much for your feedback and sorry for may delayed response.\r\n\r\n> I think the old arrangement was simple code_link where endpoints are grouped for given action (POST/PATCH) rather, this new arrangement where endpoints are tagged with action it supports.\r\n\r\nI see your point - I think that it is just a question of the point of view. The old code was grouped by the action/method, but was sometimes hard to find all endpoints for one object kind. And also to check that there are all endpoints set for all actions for a particular object kind. Now all information are grouped together and visible in one place.\r\n\r\n> So overall, see if you can fix endpoint_arrangement while still keep rest of design which provides code_reusability. If it's a lot_work then you can take one more feedback from team and see if other feel the this problem or not.\r\n\r\nI could do that, but the only thing that would be changed is the endpoints arrangement. The internal logic would stay the same (because I rely on it in other places) so I'm not sure if that would anyhow help with debugging. I'm not sure how much time that would need, maybe a few hours, maybe one day. Let's wait for the other guys what they think about it.","created_at":"2018-11-27T07:30:57Z","updated_at":"2018-11-27T07:30:57Z","html_url":"https://github.com/fabric8-services/fabric8-tenant/pull/673#discussion_r236545709","pull_request_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/comments/236545709"},"html":{"href":"https://github.com/fabric8-services/fabric8-tenant/pull/673#discussion_r236545709"},"pull_request":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673"}},"in_reply_to_id":234507033},"pull_request":{"url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673","id":227562106,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI3NTYyMTA2","html_url":"https://github.com/fabric8-services/fabric8-tenant/pull/673","diff_url":"https://github.com/fabric8-services/fabric8-tenant/pull/673.diff","patch_url":"https://github.com/fabric8-services/fabric8-tenant/pull/673.patch","issue_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/673","number":673,"state":"open","locked":false,"title":"chore: refactor core functionality to be more extensible","user":{"login":"MatousJobanek","id":1510709,"node_id":"MDQ6VXNlcjE1MTA3MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1510709?v=4","gravatar_id":"","url":"https://api.github.com/users/MatousJobanek","html_url":"https://github.com/MatousJobanek","followers_url":"https://api.github.com/users/MatousJobanek/followers","following_url":"https://api.github.com/users/MatousJobanek/following{/other_user}","gists_url":"https://api.github.com/users/MatousJobanek/gists{/gist_id}","starred_url":"https://api.github.com/users/MatousJobanek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MatousJobanek/subscriptions","organizations_url":"https://api.github.com/users/MatousJobanek/orgs","repos_url":"https://api.github.com/users/MatousJobanek/repos","events_url":"https://api.github.com/users/MatousJobanek/events{/privacy}","received_events_url":"https://api.github.com/users/MatousJobanek/received_events","type":"User","site_admin":false},"body":"This PR refactors the core logic of the tenant service that is mainly placed in `openshift` and `controller` packages.\r\nFor a better understanding of the changes (mainly in the `openshift` package), I would recommend to fetch this PR and follow the code starting from `main.go` or `controller` package, not checking the changes in GH web UI as most of the code is totally different.\r\n\r\n#### Why this PR\r\n\r\nIn the original code there were code [duplications](https://github.com/fabric8-services/fabric8-tenant/blob/master/controller/tenant.go#L271); several complicated [if-else](https://github.com/fabric8-services/fabric8-tenant/blob/master/controller/tenant.go#L271) statements to handle [exceptions](https://github.com/fabric8-services/fabric8-tenant/blob/master/openshift/init_tenant.go#L32) in the behavior; inconsistent way in creating/updating/deleting objects in OS, etc. It was really hard to extend the logic by new features and make it ready for OSIO on OSD\r\n\r\n#### Design\r\n\r\nThe new design I'm proposing in this PR encapsulates the logic in objects, which means that every environment type or action performs what is needed without any complicated if-else statements. The approach could be understood as: \r\n\"We need to perform an action(eg. POST) on an environment type (eg. Che) for a particular tenant. To do this, we need to apply a list of template objects (specific for the type) using OpenShift endpoints. Every object (eg. projectrequest, rolebinding, ...) has a different endpoint and for every HTTP method may have different strategy for handling the request or possible errors.\"\r\nThe new and most important objects proposed in the PR are:\r\n\r\n* `openshift.NamespaceAction` - Represents the action that should be applied on the namespaces for the particular tenant - [post|update|delete]. It is mainly responsible for operation on DB and provides additional information specific to the action that is needed by other objects\r\n* `cluster.ForType` - it is not a object but a function that returns cluster for environment type. This is kind of preparation for the multicluster environment - in other words, it represents cluster mapping per env-type.\r\n* `openshift.EnvironmentTypeService` - Represents service operating with information related to environment types(template, objects, cluster,...). It is responsible for getting and filtering objects to be applied, provides information (eg. needed token) specific for the particular type and performs after-apply-callback (needed by user namespace)\r\n* `openshift.ObjectEndpoints` - is list of MethodDefinitions for a particular object endpoint (eg. `/oapi/v1/projectrequests`). In other words, is saying which methods (Post/Delete/Get/Patch) are allowed to be performed for the endpoint\r\n* `openshift.MethodDefinition` - represents defined actions (beforeDoCallbacks, afterDoCallbacks,requestCreator) to be executed when the method is performed for an endpoint.\r\n* `openshift.Service` - knowing which action is requested it starts for every environment type a new goroutine. The goroutine gets template objects to be applied and the target cluster and then sends a request for every object to the OS cluster.\r\n\r\n#### The flow of every action\r\n\r\nThe flow of every action is described in comments of every action - the resulting flow should reflect the original implementation\r\n\r\n#### Benefits of the changes\r\n\r\n* since the specific logic is encapsulated inside of the objects, then it is much easier eg. to introduce any new environment (test, custom) by just adding a new implementation of the type\r\n* using the HTTP requests for all actions (update and delete) instead of oc commands gives us a possibility to easily handle errors and should be also faster (should decrease the cluster-wide update time)\r\n* since the method `ApplyAll(nsTypes ...environment.Type)` takes any number of env-types it prepares the logic to lazy initialization of single namespace. For the lazy-init also the function `filterMissingAndExisting(namespaces []*tenant.Namespace)` will be very useful\r\n* the `cluster.ForType` mapping prepares the code for multi-cluster environment\r\n* it will be much easier to introduce support for contributors in OSD spaces (creation of namespaces in spaces on OSD cluster)\r\n\r\n#### Additional notes to tests\r\n\r\nI have created `repository_stub.go` that is a stub of DB and related repository. This allows me to create unit-tests (or smaller integration tests) without having DB started. I have also changed the setup of the integration test suite that previously skipped tests in the case when DB was not started. Now, if it doesn't find any DB, then the stub is used. With this, I can easily run & debug integration tests in my IDE.\r\n\r\n#### TODO\r\n- [x]  add more tests\r\n- [x]  go through all error occurrences and add logging (mainly in `controller` package) as well as handle all errors appropriately\r\n\r\nFixes https://github.com/fabric8-services/fabric8-tenant/issues/678","created_at":"2018-11-01T09:39:25Z","updated_at":"2018-11-27T07:30:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"021fb080f139ae5f3bace8b28bd4d3b629311bdd","assignee":null,"assignees":[],"requested_reviewers":[{"login":"aslakknutsen","id":132158,"node_id":"MDQ6VXNlcjEzMjE1OA==","avatar_url":"https://avatars3.githubusercontent.com/u/132158?v=4","gravatar_id":"","url":"https://api.github.com/users/aslakknutsen","html_url":"https://github.com/aslakknutsen","followers_url":"https://api.github.com/users/aslakknutsen/followers","following_url":"https://api.github.com/users/aslakknutsen/following{/other_user}","gists_url":"https://api.github.com/users/aslakknutsen/gists{/gist_id}","starred_url":"https://api.github.com/users/aslakknutsen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aslakknutsen/subscriptions","organizations_url":"https://api.github.com/users/aslakknutsen/orgs","repos_url":"https://api.github.com/users/aslakknutsen/repos","events_url":"https://api.github.com/users/aslakknutsen/events{/privacy}","received_events_url":"https://api.github.com/users/aslakknutsen/received_events","type":"User","site_admin":false},{"login":"xcoulon","id":178502,"node_id":"MDQ6VXNlcjE3ODUwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/178502?v=4","gravatar_id":"","url":"https://api.github.com/users/xcoulon","html_url":"https://github.com/xcoulon","followers_url":"https://api.github.com/users/xcoulon/followers","following_url":"https://api.github.com/users/xcoulon/following{/other_user}","gists_url":"https://api.github.com/users/xcoulon/gists{/gist_id}","starred_url":"https://api.github.com/users/xcoulon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xcoulon/subscriptions","organizations_url":"https://api.github.com/users/xcoulon/orgs","repos_url":"https://api.github.com/users/xcoulon/repos","events_url":"https://api.github.com/users/xcoulon/events{/privacy}","received_events_url":"https://api.github.com/users/xcoulon/received_events","type":"User","site_admin":false},{"login":"alexeykazakov","id":620087,"node_id":"MDQ6VXNlcjYyMDA4Nw==","avatar_url":"https://avatars3.githubusercontent.com/u/620087?v=4","gravatar_id":"","url":"https://api.github.com/users/alexeykazakov","html_url":"https://github.com/alexeykazakov","followers_url":"https://api.github.com/users/alexeykazakov/followers","following_url":"https://api.github.com/users/alexeykazakov/following{/other_user}","gists_url":"https://api.github.com/users/alexeykazakov/gists{/gist_id}","starred_url":"https://api.github.com/users/alexeykazakov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexeykazakov/subscriptions","organizations_url":"https://api.github.com/users/alexeykazakov/orgs","repos_url":"https://api.github.com/users/alexeykazakov/repos","events_url":"https://api.github.com/users/alexeykazakov/events{/privacy}","received_events_url":"https://api.github.com/users/alexeykazakov/received_events","type":"User","site_admin":false},{"login":"dipak-pawar","id":7941617,"node_id":"MDQ6VXNlcjc5NDE2MTc=","avatar_url":"https://avatars3.githubusercontent.com/u/7941617?v=4","gravatar_id":"","url":"https://api.github.com/users/dipak-pawar","html_url":"https://github.com/dipak-pawar","followers_url":"https://api.github.com/users/dipak-pawar/followers","following_url":"https://api.github.com/users/dipak-pawar/following{/other_user}","gists_url":"https://api.github.com/users/dipak-pawar/gists{/gist_id}","starred_url":"https://api.github.com/users/dipak-pawar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dipak-pawar/subscriptions","organizations_url":"https://api.github.com/users/dipak-pawar/orgs","repos_url":"https://api.github.com/users/dipak-pawar/repos","events_url":"https://api.github.com/users/dipak-pawar/events{/privacy}","received_events_url":"https://api.github.com/users/dipak-pawar/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673/commits","review_comments_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673/comments","review_comment_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/comments{/number}","comments_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/673/comments","statuses_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/statuses/a07dd9cf79f92ce20dd136a0f95c74ffdfaf0a40","head":{"label":"MatousJobanek:core-v2-merge","ref":"core-v2-merge","sha":"a07dd9cf79f92ce20dd136a0f95c74ffdfaf0a40","user":{"login":"MatousJobanek","id":1510709,"node_id":"MDQ6VXNlcjE1MTA3MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1510709?v=4","gravatar_id":"","url":"https://api.github.com/users/MatousJobanek","html_url":"https://github.com/MatousJobanek","followers_url":"https://api.github.com/users/MatousJobanek/followers","following_url":"https://api.github.com/users/MatousJobanek/following{/other_user}","gists_url":"https://api.github.com/users/MatousJobanek/gists{/gist_id}","starred_url":"https://api.github.com/users/MatousJobanek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MatousJobanek/subscriptions","organizations_url":"https://api.github.com/users/MatousJobanek/orgs","repos_url":"https://api.github.com/users/MatousJobanek/repos","events_url":"https://api.github.com/users/MatousJobanek/events{/privacy}","received_events_url":"https://api.github.com/users/MatousJobanek/received_events","type":"User","site_admin":false},"repo":{"id":141242074,"node_id":"MDEwOlJlcG9zaXRvcnkxNDEyNDIwNzQ=","name":"fabric8-tenant","full_name":"MatousJobanek/fabric8-tenant","private":false,"owner":{"login":"MatousJobanek","id":1510709,"node_id":"MDQ6VXNlcjE1MTA3MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1510709?v=4","gravatar_id":"","url":"https://api.github.com/users/MatousJobanek","html_url":"https://github.com/MatousJobanek","followers_url":"https://api.github.com/users/MatousJobanek/followers","following_url":"https://api.github.com/users/MatousJobanek/following{/other_user}","gists_url":"https://api.github.com/users/MatousJobanek/gists{/gist_id}","starred_url":"https://api.github.com/users/MatousJobanek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MatousJobanek/subscriptions","organizations_url":"https://api.github.com/users/MatousJobanek/orgs","repos_url":"https://api.github.com/users/MatousJobanek/repos","events_url":"https://api.github.com/users/MatousJobanek/events{/privacy}","received_events_url":"https://api.github.com/users/MatousJobanek/received_events","type":"User","site_admin":false},"html_url":"https://github.com/MatousJobanek/fabric8-tenant","description":"Service responsible for provisioning and updating the tenant scoped services","fork":true,"url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant","forks_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/forks","keys_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/teams","hooks_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/hooks","issue_events_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/issues/events{/number}","events_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/events","assignees_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/assignees{/user}","branches_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/branches{/branch}","tags_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/tags","blobs_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/git/refs{/sha}","trees_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/statuses/{sha}","languages_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/languages","stargazers_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/stargazers","contributors_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/contributors","subscribers_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/subscribers","subscription_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/subscription","commits_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/commits{/sha}","git_commits_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/git/commits{/sha}","comments_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/comments{/number}","issue_comment_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/issues/comments{/number}","contents_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/contents/{+path}","compare_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/merges","archive_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/downloads","issues_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/issues{/number}","pulls_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/pulls{/number}","milestones_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/milestones{/number}","notifications_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/labels{/name}","releases_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/releases{/id}","deployments_url":"https://api.github.com/repos/MatousJobanek/fabric8-tenant/deployments","created_at":"2018-07-17T06:29:54Z","updated_at":"2018-07-17T06:29:56Z","pushed_at":"2018-11-27T05:52:41Z","git_url":"git://github.com/MatousJobanek/fabric8-tenant.git","ssh_url":"git@github.com:MatousJobanek/fabric8-tenant.git","clone_url":"https://github.com/MatousJobanek/fabric8-tenant.git","svn_url":"https://github.com/MatousJobanek/fabric8-tenant","homepage":"","size":1214,"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":"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":"fabric8-services:master","ref":"master","sha":"9b2288f82052207df439b18ef5d867ebd6759848","user":{"login":"fabric8-services","id":29751612,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5NzUxNjEy","avatar_url":"https://avatars1.githubusercontent.com/u/29751612?v=4","gravatar_id":"","url":"https://api.github.com/users/fabric8-services","html_url":"https://github.com/fabric8-services","followers_url":"https://api.github.com/users/fabric8-services/followers","following_url":"https://api.github.com/users/fabric8-services/following{/other_user}","gists_url":"https://api.github.com/users/fabric8-services/gists{/gist_id}","starred_url":"https://api.github.com/users/fabric8-services/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabric8-services/subscriptions","organizations_url":"https://api.github.com/users/fabric8-services/orgs","repos_url":"https://api.github.com/users/fabric8-services/repos","events_url":"https://api.github.com/users/fabric8-services/events{/privacy}","received_events_url":"https://api.github.com/users/fabric8-services/received_events","type":"Organization","site_admin":false},"repo":{"id":85101045,"node_id":"MDEwOlJlcG9zaXRvcnk4NTEwMTA0NQ==","name":"fabric8-tenant","full_name":"fabric8-services/fabric8-tenant","private":false,"owner":{"login":"fabric8-services","id":29751612,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5NzUxNjEy","avatar_url":"https://avatars1.githubusercontent.com/u/29751612?v=4","gravatar_id":"","url":"https://api.github.com/users/fabric8-services","html_url":"https://github.com/fabric8-services","followers_url":"https://api.github.com/users/fabric8-services/followers","following_url":"https://api.github.com/users/fabric8-services/following{/other_user}","gists_url":"https://api.github.com/users/fabric8-services/gists{/gist_id}","starred_url":"https://api.github.com/users/fabric8-services/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabric8-services/subscriptions","organizations_url":"https://api.github.com/users/fabric8-services/orgs","repos_url":"https://api.github.com/users/fabric8-services/repos","events_url":"https://api.github.com/users/fabric8-services/events{/privacy}","received_events_url":"https://api.github.com/users/fabric8-services/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/fabric8-services/fabric8-tenant","description":"Service responsible for provisioning and updating the tenant scoped services","fork":false,"url":"https://api.github.com/repos/fabric8-services/fabric8-tenant","forks_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/forks","keys_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/teams","hooks_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/hooks","issue_events_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/events{/number}","events_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/events","assignees_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/assignees{/user}","branches_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/branches{/branch}","tags_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/tags","blobs_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/git/refs{/sha}","trees_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/statuses/{sha}","languages_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/languages","stargazers_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/stargazers","contributors_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/contributors","subscribers_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/subscribers","subscription_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/subscription","commits_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/commits{/sha}","git_commits_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/git/commits{/sha}","comments_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/comments{/number}","issue_comment_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/comments{/number}","contents_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/contents/{+path}","compare_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/merges","archive_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/downloads","issues_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues{/number}","pulls_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls{/number}","milestones_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/milestones{/number}","notifications_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/labels{/name}","releases_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/releases{/id}","deployments_url":"https://api.github.com/repos/fabric8-services/fabric8-tenant/deployments","created_at":"2017-03-15T17:22:51Z","updated_at":"2018-11-27T06:52:17Z","pushed_at":"2018-11-27T06:52:15Z","git_url":"git://github.com/fabric8-services/fabric8-tenant.git","ssh_url":"git@github.com:fabric8-services/fabric8-tenant.git","clone_url":"https://github.com/fabric8-services/fabric8-tenant.git","svn_url":"https://github.com/fabric8-services/fabric8-tenant","homepage":"","size":827,"stargazers_count":6,"watchers_count":6,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":29,"mirror_url":null,"archived":false,"open_issues_count":19,"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":29,"open_issues":19,"watchers":6,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673"},"html":{"href":"https://github.com/fabric8-services/fabric8-tenant/pull/673"},"issue":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/673"},"comments":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/issues/673/comments"},"review_comments":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673/comments"},"review_comment":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/pulls/673/commits"},"statuses":{"href":"https://api.github.com/repos/fabric8-services/fabric8-tenant/statuses/a07dd9cf79f92ce20dd136a0f95c74ffdfaf0a40"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"MatousJobanek"}}