{"action":"created","comment":{"url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/comments/212961832","pull_request_review_id":149695503,"id":212961832,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMjk2MTgzMg==","diff_hunk":"@@ -0,0 +1,514 @@\n+package rules\n+\n+import (\n+\t\"context\"\n+\t\"encoding/json\"\n+\t\"github.com/fabric8-services/fabric8-wit/actions/change\"\n+\n+\terrs \"github.com/pkg/errors\"\n+\tuuid \"github.com/satori/go.uuid\"\n+\n+\t\"github.com/fabric8-services/fabric8-wit/application\"\n+\t\"github.com/fabric8-services/fabric8-wit/workitem\"\n+)\n+\n+// ActionStateToMetaState implements the bidirectional mapping between state and column.\n+type ActionStateToMetaState struct {\n+\tDb     application.DB\n+\tCtx    context.Context\n+\tUserID *uuid.UUID\n+}\n+\n+// make sure the rule is implementing the interface.\n+var _ Action = ActionStateToMetaState{}\n+\n+func (act ActionStateToMetaState) containsUUID(s []uuid.UUID, e uuid.UUID) bool {\n+\tfor _, a := range s {\n+\t\tif a == e {\n+\t\t\treturn true\n+\t\t}\n+\t}\n+\treturn false\n+}\n+\n+func (act ActionStateToMetaState) contains(s []interface{}, e interface{}) bool {\n+\tfor _, a := range s {\n+\t\tif a == e {\n+\t\t\treturn true\n+\t\t}\n+\t}\n+\treturn false\n+}\n+\n+func (act ActionStateToMetaState) removeElement(s []interface{}, e interface{}) []interface{} {\n+\tfor idx, a := range s {\n+\t\tif a == e {\n+\t\t\ts = append(s[:idx], s[idx+1:]...)\n+\t\t\t// we don't return here as there may be multiple copies of e in s.\n+\t\t}\n+\t}\n+\treturn s\n+}\n+\n+// difference returns the differences between two slices. It returns two slices containing\n+// the added and removed elements compared from old and new arguments.\n+func (act ActionStateToMetaState) difference(old []interface{}, new []interface{}) ([]interface{}, []interface{}) {\n+\tvar added []interface{}\n+\tvar removed []interface{}\n+\t// added in slice2\n+\tfor _, elem := range new {\n+\t\tif !act.contains(old, elem) {\n+\t\t\tadded = append(added, elem)\n+\t\t}\n+\t}\n+\t// removed in slice2\n+\tfor _, elem := range old {\n+\t\tif !act.contains(new, elem) {\n+\t\t\tremoved = append(removed, elem)\n+\t\t}\n+\t}\n+\treturn added, removed\n+}\n+\n+func (act ActionStateToMetaState) loadWorkItemBoardsBySpaceID(spaceID uuid.UUID) ([]*workitem.Board, error) {\n+\tif act.Ctx == nil {\n+\t\treturn nil, errs.New(\"context is nil\")\n+\t}\n+\tif act.Db == nil {\n+\t\treturn nil, errs.New(\"database is nil\")\n+\t}\n+\tspace, err := act.Db.Spaces().Load(act.Ctx, spaceID)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading space: \"+err.Error())\n+\t}\n+\tboards, err := act.Db.Boards().List(act.Ctx, space.SpaceTemplateID)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading work item type: \"+err.Error())\n+\t}\n+\treturn boards, nil\n+}\n+\n+func (act ActionStateToMetaState) loadWorkItemTypeGroupsBySpaceID(spaceID uuid.UUID) ([]*workitem.WorkItemTypeGroup, error) {\n+\tif act.Ctx == nil {\n+\t\treturn nil, errs.New(\"context is nil\")\n+\t}\n+\tif act.Db == nil {\n+\t\treturn nil, errs.New(\"database is nil\")\n+\t}\n+\tspace, err := act.Db.Spaces().Load(act.Ctx, spaceID)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading space: \"+err.Error())\n+\t}\n+\tgroups, err := act.Db.WorkItemTypeGroups().List(act.Ctx, space.SpaceTemplateID)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading work item type: \"+err.Error())\n+\t}\n+\treturn groups, nil\n+}\n+\n+func (act ActionStateToMetaState) loadWorkItemTypeByID(id uuid.UUID) (*workitem.WorkItemType, error) {\n+\tif act.Ctx == nil {\n+\t\treturn nil, errs.New(\"context is nil\")\n+\t}\n+\tif act.Db == nil {\n+\t\treturn nil, errs.New(\"database is nil\")\n+\t}\n+\twit, err := act.Db.WorkItemTypes().Load(act.Ctx, id)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading work item type: \"+err.Error())\n+\t}\n+\treturn wit, nil\n+}\n+\n+func (act ActionStateToMetaState) loadWorkItemByID(id uuid.UUID) (*workitem.WorkItem, error) {\n+\tif act.Ctx == nil {\n+\t\treturn nil, errs.New(\"context is nil\")\n+\t}\n+\tif act.Db == nil {\n+\t\treturn nil, errs.New(\"database is nil\")\n+\t}\n+\twi, err := act.Db.WorkItems().LoadByID(act.Ctx, id)\n+\tif err != nil {\n+\t\treturn nil, errs.Wrap(err, \"error loading work item: \"+err.Error())\n+\t}\n+\treturn wi, nil\n+}\n+\n+func (act ActionStateToMetaState) storeWorkItem(workitem *workitem.WorkItem) (*workitem.WorkItem, error) {\n+\tif act.Ctx == nil {\n+\t\treturn nil, errs.New(\"context is nil\")\n+\t}\n+\tif act.Db == nil {\n+\t\treturn nil, errs.New(\"database is nil\")\n+\t}\n+\tif act.UserID == nil {\n+\t\treturn nil, errs.New(\"userID is nil\")\n+\t}\n+\terr := application.Transactional(act.Db, func(appl application.Application) error {\n+\t\tvar err error\n+\t\tworkitem, err = appl.WorkItems().Save(act.Ctx, workitem.SpaceID, *workitem, *act.UserID)\n+\t\tif err != nil {\n+\t\t\treturn errs.Wrap(err, \"error updating work item\")\n+\t\t}\n+\t\treturn nil\n+\t})\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\treturn workitem, nil\n+}\n+\n+func (act ActionStateToMetaState) getValueListFromFieldType(wit *workitem.WorkItemType, fieldName string) ([]interface{}, error) {\n+\tfieldType := wit.Fields[fieldName].Type\n+\tswitch t := fieldType.(type) {\n+\tcase workitem.EnumType:\n+\t\treturn t.Values, nil\n+\t}\n+\treturn nil, errs.New(\"given field on workitemtype \" + wit.ID.String() + \" is not an enum field: \" + fieldName)\n+}\n+\n+func (act ActionStateToMetaState) getStateToMetastateMap(workitemTypeID uuid.UUID) (map[string]string, error) {\n+\twit, err := act.loadWorkItemTypeByID(workitemTypeID)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tstateList, err := act.getValueListFromFieldType(wit, workitem.SystemState)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tmetastateList, err := act.getValueListFromFieldType(wit, workitem.SystemMetaState)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tif len(stateList) != len(metastateList) {\n+\t\treturn nil, errs.New(\"inconsistent number of states and metatstates in the current work item type (must be equal)\")\n+\t}\n+\tstateToMetastateMap := make(map[string]string)\n+\tfor idx := range stateList {\n+\t\tthisState, ok := stateList[idx].(string)\n+\t\tif !ok {\n+\t\t\treturn nil, errs.New(\"state value in value list is not of type string\")\n+\t\t}\n+\t\tthisMetastate, ok := metastateList[idx].(string)\n+\t\tif !ok {\n+\t\t\treturn nil, errs.New(\"metastate value in value list is not of type string\")\n+\t\t}\n+\t\t// this is important: we only add a new entry if there\n+\t\t// is not an entry already existing. Therefore, we're only\n+\t\t// using the first mapping, satisfying the req for getting the\n+\t\t// first matching metastate for a state.\n+\t\t// this is done here even if the usecase where we have\n+\t\t// multiple states with the same value (duplicate states)\n+\t\t// might be not that common.\n+\t\tif _, ok := stateToMetastateMap[thisState]; !ok {\n+\t\t\tstateToMetastateMap[thisState] = thisMetastate\n+\t\t}\n+\t}\n+\treturn stateToMetastateMap, nil\n+}\n+\n+func (act ActionStateToMetaState) getMetastateToStateMap(workitemTypeID uuid.UUID) (map[string]string, error) {\n+\tstateToMetastate, err := act.getStateToMetastateMap(workitemTypeID)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tmetastateToStateMap := make(map[string]string)\n+\tfor state, metastate := range stateToMetastate {\n+\t\t// this is important: we only add a new entry if there\n+\t\t// is not an entry already existing. Therefore, we're only\n+\t\t// using the first mapping, satisfying the req for getting the\n+\t\t// first matching state for a metastate.\n+\t\tif _, ok := metastateToStateMap[metastate]; !ok {\n+\t\t\tmetastateToStateMap[metastate] = state\n+\t\t}\n+\t}\n+\treturn metastateToStateMap, nil\n+}\n+\n+func (act ActionStateToMetaState) addOrUpdateChange(changes change.Set, attributeName string, oldValue interface{}, newValue interface{}) change.Set {\n+\tfor _, change := range changes {\n+\t\tif change.AttributeName == attributeName {\n+\t\t\tchange.NewValue = newValue\n+\t\t\treturn changes\n+\t\t}\n+\t}\n+\tnewChanges := append(changes, change.Change{\n+\t\tAttributeName: attributeName,\n+\t\tOldValue:      oldValue,\n+\t\tNewValue:      newValue,\n+\t})\n+\treturn newChanges\n+}\n+\n+func (act ActionStateToMetaState) fuseChanges(c1 change.Set, c2 change.Set) *change.Set {\n+\tfor _, change := range c2 {\n+\t\tc1 = act.addOrUpdateChange(c1, change.AttributeName, change.OldValue, change.NewValue)\n+\t}\n+\treturn &c1\n+}\n+\n+// OnChange executes the action rule.\n+func (act ActionStateToMetaState) OnChange(newContext change.Detector, contextChanges change.Set, configuration string, actionChanges *change.Set) (change.Detector, change.Set, error) {\n+\tif actionChanges == nil {\n+\t\treturn nil, nil, errs.New(\"given actionChanges is nil\")\n+\t}\n+\tif len(contextChanges) == 0 {\n+\t\t// no changes, just return what we have.\n+\t\treturn newContext, *actionChanges, nil\n+\t}\n+\t// if we have multiple changes, this iterates over them and cherrypicks, fusing the results together.\n+\tvar err error\n+\tvar executionChanges change.Set\n+\tfor _, change := range contextChanges {\n+\t\tif change.AttributeName == workitem.SystemState {\n+\t\t\tnewContext, executionChanges, err = act.OnStateChange(newContext, contextChanges, configuration, actionChanges)\n+\t\t}\n+\t\tif change.AttributeName == workitem.SystemBoardcolumns {\n+\t\t\tnewContext, executionChanges, err = act.OnBoardColumnsChange(newContext, contextChanges, configuration, actionChanges)\n+\t\t}\n+\t\tif err != nil {\n+\t\t\treturn nil, nil, err\n+\t\t}\n+\t\tactionChanges = act.fuseChanges(*actionChanges, executionChanges)\n+\t}\n+\t// return the result\n+\treturn newContext, *actionChanges, nil\n+}\n+\n+// OnBoardColumnsChange is executed when the columns change. It eventually updates the metastate and the state.\n+func (act ActionStateToMetaState) OnBoardColumnsChange(newContext change.Detector, contextChanges change.Set, configuration string, actionChanges *change.Set) (change.Detector, change.Set, error) {\n+\t// we already assume that the rule applies, this needs to be checked in the controller.\n+\t// there is no additional check on the rule key.\n+\twi, ok := newContext.(workitem.WorkItem)\n+\tif !ok {\n+\t\treturn nil, nil, errs.New(\"given context is not a WorkItem instance\")\n+\t}\n+\t// extract columns that changed from oldValue newValue\n+\tvar columnsAdded []interface{}\n+\tfor _, change := range contextChanges {\n+\t\tif change.AttributeName == workitem.SystemBoardcolumns {\n+\t\t\tvar oldValue []interface{}\n+\t\t\toldValue, ok := change.OldValue.([]interface{})\n+\t\t\tif !ok && change.OldValue != nil {\n+\t\t\t\t// OldValue may be nil, so only throw error when non-nil and\n+\t\t\t\t// can not convert.\n+\t\t\t\treturn nil, nil, errs.New(\"error converting oldValue set\")\n+\t\t\t}\n+\t\t\tnewValue, ok := change.NewValue.([]interface{})\n+\t\t\tif !ok {\n+\t\t\t\treturn nil, nil, errs.New(\"error converting newValue set\")\n+\t\t\t}\n+\t\t\tcolumnsAdded, _ = act.difference(oldValue, newValue)\n+\t\t}\n+\t}\n+\t// from here on, we ignore the removed columns as a possible metastate transition is\n+\t// only happening on *adding* a new column. Removing column does not trigger a change.\n+\tif len(columnsAdded) == 0 {\n+\t\t// somehow, no actual changes on the columns.\n+\t\treturn newContext, *actionChanges, nil\n+\t}\n+\t// get the mapping.\n+\tmapping, err := act.getMetastateToStateMap(wi.Type)\n+\tif err != nil {\n+\t\treturn nil, nil, err\n+\t}\n+\t// create a dirty flag. Note that we can not use len(actionChanges) as this\n+\t// may contain previous changes from the action chain.\n+\twiDirty := false\n+\tvar changes change.Set\n+\t// go over all added columns. We support multiple added columns at once.\n+\tfor _, columnID := range columnsAdded {\n+\t\t// get board and column by columnID.\n+\t\tvar thisColumn workitem.BoardColumn\n+\t\tboards, err := act.loadWorkItemBoardsBySpaceID(wi.SpaceID)\n+\t\tif err != nil {\n+\t\t\treturn nil, nil, err\n+\t\t}\n+\t\tfor _, board := range boards {\n+\t\t\tfor _, column := range board.Columns {\n+\t\t\t\tif columnID == column.ID.String() {\n+\t\t\t\t\tthisColumn = column","path":"actions/rules/action_state_to_metastate.go","position":284,"original_position":330,"commit_id":"5b4d19cf4bb52ae0161b49d944a3464001aa234c","original_commit_id":"94ca51e5b3d2629fb61703a15233a02ef389d52b","user":{"login":"kwk","id":193408,"node_id":"MDQ6VXNlcjE5MzQwOA==","avatar_url":"https://avatars3.githubusercontent.com/u/193408?v=4","gravatar_id":"","url":"https://api.github.com/users/kwk","html_url":"https://github.com/kwk","followers_url":"https://api.github.com/users/kwk/followers","following_url":"https://api.github.com/users/kwk/following{/other_user}","gists_url":"https://api.github.com/users/kwk/gists{/gist_id}","starred_url":"https://api.github.com/users/kwk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kwk/subscriptions","organizations_url":"https://api.github.com/users/kwk/orgs","repos_url":"https://api.github.com/users/kwk/repos","events_url":"https://api.github.com/users/kwk/events{/privacy}","received_events_url":"https://api.github.com/users/kwk/received_events","type":"User","site_admin":false},"body":"Okay. I'm fine with this.","created_at":"2018-08-27T12:49:01Z","updated_at":"2018-08-27T12:49:01Z","html_url":"https://github.com/fabric8-services/fabric8-wit/pull/2249#discussion_r212961832","pull_request_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/comments/212961832"},"html":{"href":"https://github.com/fabric8-services/fabric8-wit/pull/2249#discussion_r212961832"},"pull_request":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249"}},"in_reply_to_id":212307238},"pull_request":{"url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249","id":209488904,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA5NDg4OTA0","html_url":"https://github.com/fabric8-services/fabric8-wit/pull/2249","diff_url":"https://github.com/fabric8-services/fabric8-wit/pull/2249.diff","patch_url":"https://github.com/fabric8-services/fabric8-wit/pull/2249.patch","issue_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/2249","number":2249,"state":"open","locked":false,"title":"Actions Board View Rule","user":{"login":"michaelkleinhenz","id":7101098,"node_id":"MDQ6VXNlcjcxMDEwOTg=","avatar_url":"https://avatars1.githubusercontent.com/u/7101098?v=4","gravatar_id":"","url":"https://api.github.com/users/michaelkleinhenz","html_url":"https://github.com/michaelkleinhenz","followers_url":"https://api.github.com/users/michaelkleinhenz/followers","following_url":"https://api.github.com/users/michaelkleinhenz/following{/other_user}","gists_url":"https://api.github.com/users/michaelkleinhenz/gists{/gist_id}","starred_url":"https://api.github.com/users/michaelkleinhenz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/michaelkleinhenz/subscriptions","organizations_url":"https://api.github.com/users/michaelkleinhenz/orgs","repos_url":"https://api.github.com/users/michaelkleinhenz/repos","events_url":"https://api.github.com/users/michaelkleinhenz/events{/privacy}","received_events_url":"https://api.github.com/users/michaelkleinhenz/received_events","type":"User","site_admin":false},"body":"This contains the state to metastate mapping action rule and the necessary changes to the existing templates.\r\n\r\nPlease note that this PR contains 2 new source files (the actual rule and the test) and minor changes to 3 existing files. The rest of the files in the PR are changes to golden files.","created_at":"2018-08-20T11:19:18Z","updated_at":"2018-08-27T12:49:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bbe24c44cad97401d0e62557a05d3ede4053e134","assignee":null,"assignees":[],"requested_reviewers":[{"login":"jarifibrahim","id":12949454,"node_id":"MDQ6VXNlcjEyOTQ5NDU0","avatar_url":"https://avatars3.githubusercontent.com/u/12949454?v=4","gravatar_id":"","url":"https://api.github.com/users/jarifibrahim","html_url":"https://github.com/jarifibrahim","followers_url":"https://api.github.com/users/jarifibrahim/followers","following_url":"https://api.github.com/users/jarifibrahim/following{/other_user}","gists_url":"https://api.github.com/users/jarifibrahim/gists{/gist_id}","starred_url":"https://api.github.com/users/jarifibrahim/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jarifibrahim/subscriptions","organizations_url":"https://api.github.com/users/jarifibrahim/orgs","repos_url":"https://api.github.com/users/jarifibrahim/repos","events_url":"https://api.github.com/users/jarifibrahim/events{/privacy}","received_events_url":"https://api.github.com/users/jarifibrahim/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249/commits","review_comments_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249/comments","review_comment_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/2249/comments","statuses_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/statuses/5b4d19cf4bb52ae0161b49d944a3464001aa234c","head":{"label":"michaelkleinhenz:actions_staterule","ref":"actions_staterule","sha":"5b4d19cf4bb52ae0161b49d944a3464001aa234c","user":{"login":"michaelkleinhenz","id":7101098,"node_id":"MDQ6VXNlcjcxMDEwOTg=","avatar_url":"https://avatars1.githubusercontent.com/u/7101098?v=4","gravatar_id":"","url":"https://api.github.com/users/michaelkleinhenz","html_url":"https://github.com/michaelkleinhenz","followers_url":"https://api.github.com/users/michaelkleinhenz/followers","following_url":"https://api.github.com/users/michaelkleinhenz/following{/other_user}","gists_url":"https://api.github.com/users/michaelkleinhenz/gists{/gist_id}","starred_url":"https://api.github.com/users/michaelkleinhenz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/michaelkleinhenz/subscriptions","organizations_url":"https://api.github.com/users/michaelkleinhenz/orgs","repos_url":"https://api.github.com/users/michaelkleinhenz/repos","events_url":"https://api.github.com/users/michaelkleinhenz/events{/privacy}","received_events_url":"https://api.github.com/users/michaelkleinhenz/received_events","type":"User","site_admin":false},"repo":{"id":131597385,"node_id":"MDEwOlJlcG9zaXRvcnkxMzE1OTczODU=","name":"fabric8-wit","full_name":"michaelkleinhenz/fabric8-wit","owner":{"login":"michaelkleinhenz","id":7101098,"node_id":"MDQ6VXNlcjcxMDEwOTg=","avatar_url":"https://avatars1.githubusercontent.com/u/7101098?v=4","gravatar_id":"","url":"https://api.github.com/users/michaelkleinhenz","html_url":"https://github.com/michaelkleinhenz","followers_url":"https://api.github.com/users/michaelkleinhenz/followers","following_url":"https://api.github.com/users/michaelkleinhenz/following{/other_user}","gists_url":"https://api.github.com/users/michaelkleinhenz/gists{/gist_id}","starred_url":"https://api.github.com/users/michaelkleinhenz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/michaelkleinhenz/subscriptions","organizations_url":"https://api.github.com/users/michaelkleinhenz/orgs","repos_url":"https://api.github.com/users/michaelkleinhenz/repos","events_url":"https://api.github.com/users/michaelkleinhenz/events{/privacy}","received_events_url":"https://api.github.com/users/michaelkleinhenz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/michaelkleinhenz/fabric8-wit","description":null,"fork":true,"url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit","forks_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/forks","keys_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/teams","hooks_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/hooks","issue_events_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/issues/events{/number}","events_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/events","assignees_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/assignees{/user}","branches_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/branches{/branch}","tags_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/tags","blobs_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/git/refs{/sha}","trees_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/statuses/{sha}","languages_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/languages","stargazers_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/stargazers","contributors_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/contributors","subscribers_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/subscribers","subscription_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/subscription","commits_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/commits{/sha}","git_commits_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/git/commits{/sha}","comments_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/comments{/number}","issue_comment_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/issues/comments{/number}","contents_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/contents/{+path}","compare_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/merges","archive_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/downloads","issues_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/issues{/number}","pulls_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/pulls{/number}","milestones_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/milestones{/number}","notifications_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/labels{/name}","releases_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/releases{/id}","deployments_url":"https://api.github.com/repos/michaelkleinhenz/fabric8-wit/deployments","created_at":"2018-04-30T13:11:46Z","updated_at":"2018-08-03T07:09:24Z","pushed_at":"2018-08-27T12:20:24Z","git_url":"git://github.com/michaelkleinhenz/fabric8-wit.git","ssh_url":"git@github.com:michaelkleinhenz/fabric8-wit.git","clone_url":"https://github.com/michaelkleinhenz/fabric8-wit.git","svn_url":"https://github.com/michaelkleinhenz/fabric8-wit","homepage":"http://devdoc.almighty.io/","size":9153,"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":"fabric8-services:master","ref":"master","sha":"1ca1860b8ac8c97de8bb72be82679263b8ddcbed","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":54260706,"node_id":"MDEwOlJlcG9zaXRvcnk1NDI2MDcwNg==","name":"fabric8-wit","full_name":"fabric8-services/fabric8-wit","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},"private":false,"html_url":"https://github.com/fabric8-services/fabric8-wit","description":null,"fork":false,"url":"https://api.github.com/repos/fabric8-services/fabric8-wit","forks_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/forks","keys_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/teams","hooks_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/hooks","issue_events_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/events{/number}","events_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/events","assignees_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/assignees{/user}","branches_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/branches{/branch}","tags_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/tags","blobs_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/git/refs{/sha}","trees_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/statuses/{sha}","languages_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/languages","stargazers_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/stargazers","contributors_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/contributors","subscribers_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/subscribers","subscription_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/subscription","commits_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/commits{/sha}","git_commits_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/git/commits{/sha}","comments_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/comments{/number}","issue_comment_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/comments{/number}","contents_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/contents/{+path}","compare_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/merges","archive_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/downloads","issues_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues{/number}","pulls_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls{/number}","milestones_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/milestones{/number}","notifications_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/labels{/name}","releases_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/releases{/id}","deployments_url":"https://api.github.com/repos/fabric8-services/fabric8-wit/deployments","created_at":"2016-03-19T10:42:15Z","updated_at":"2018-08-27T12:10:27Z","pushed_at":"2018-08-27T12:20:26Z","git_url":"git://github.com/fabric8-services/fabric8-wit.git","ssh_url":"git@github.com:fabric8-services/fabric8-wit.git","clone_url":"https://github.com/fabric8-services/fabric8-wit.git","svn_url":"https://github.com/fabric8-services/fabric8-wit","homepage":"http://devdoc.almighty.io/","size":13364,"stargazers_count":38,"watchers_count":38,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":80,"mirror_url":null,"archived":false,"open_issues_count":196,"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":80,"open_issues":196,"watchers":38,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249"},"html":{"href":"https://github.com/fabric8-services/fabric8-wit/pull/2249"},"issue":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/2249"},"comments":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/issues/2249/comments"},"review_comments":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249/comments"},"review_comment":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/pulls/2249/commits"},"statuses":{"href":"https://api.github.com/repos/fabric8-services/fabric8-wit/statuses/5b4d19cf4bb52ae0161b49d944a3464001aa234c"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"kwk"}}