{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/41475438","id":41475438,"diff_hunk":"@@ -827,3 +881,85 @@ func sliceElementType(slices ...[]interface{}) (reflect.Type, error) {\n \n \treturn prevType, nil\n }\n+\n+// CreateThreeWayMergePatch reconciles a modified configuration with an original configuration,\n+// while preserving any changes or deletions made to the original configuration in the interim,\n+// and not overridden by the current configuration. All three documents must be passed to the\n+// method as json encoded content. It will return a strategic merge patch, or an error if any\n+// of the documents is invalid, or if there are any preconditions that fail against the modified\n+// configuration, or, if force is false and there are conflicts between the modified and current\n+// configurations.\n+func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct interface{}, force bool, fns ...PreconditionFunc) ([]byte, error) {\n+\toriginalMap := map[string]interface{}{}\n+\tif len(original) > 0 {\n+\t\tif err := json.Unmarshal(original, &originalMap); err != nil {\n+\t\t\treturn nil, errBadJSONDoc\n+\t\t}\n+\t}\n+\n+\tmodifiedMap := map[string]interface{}{}\n+\tif len(modified) > 0 {\n+\t\tif err := json.Unmarshal(modified, &modifiedMap); err != nil {\n+\t\t\treturn nil, errBadJSONDoc\n+\t\t}\n+\t}\n+\n+\tcurrentMap := map[string]interface{}{}\n+\tif len(current) > 0 {\n+\t\tif err := json.Unmarshal(current, &currentMap); err != nil {\n+\t\t\treturn nil, errBadJSONDoc\n+\t\t}\n+\t}\n+\n+\tt, err := getTagStructType(dataStruct)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\t// The patch is the difference from current to modified without deletions, plus deletions\n+\t// from original to modified. To find it, we compute deletions, which are the deletions from\n+\t// original to modified, and delta, which is the difference from current to modified without\n+\t// deletions, and then apply delta to deletions as a patch, which should be strictly additive.\n+\tdeltaMap, err := diffMaps(currentMap, modifiedMap, t, false, true)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\tdeletionsMap, err := diffMaps(originalMap, modifiedMap, t, true, false)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\tpatchMap, err := mergeMap(deletionsMap, deltaMap, t)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\t// Apply the preconditions to the patch, and return an error if any of them fail.\n+\tfor _, fn := range fns {\n+\t\tif !fn(patchMap) {\n+\t\t\treturn nil, ErrPreconditionFailed\n+\t\t}\n+\t}\n+\n+\t// TODO(jackgr): If the force parameter is false, and the patch contains any keys that are not in\n+\t// original, then return a conflict error.\n+\n+\treturn json.Marshal(patchMap)\n+}\n+\n+// IsConflicting returns true if the provided error indicates a\n+// conflict exists between the original changes and the applied\n+// changes.\n+func IsConflicting(err error) bool {\n+\treturn err == ErrConflict\n+}\n+\n+// IsPreconditionFailed returns true if the provided error indicates\n+// a Delta precondition did not succeed.\n+func IsPreconditionFailed(err error) bool {\n+\treturn err == ErrPreconditionFailed","path":"pkg/util/strategicpatch/patch.go","position":null,"original_position":521,"commit_id":"ddda379b1b20ef59a9699237ef36afc83f8fe39c","original_commit_id":"aa65108d6633ed3cafd4880d4463d6a5374395e7","user":{"login":"jackgr","id":5607565,"avatar_url":"https://avatars.githubusercontent.com/u/5607565?v=3","gravatar_id":"","url":"https://api.github.com/users/jackgr","html_url":"https://github.com/jackgr","followers_url":"https://api.github.com/users/jackgr/followers","following_url":"https://api.github.com/users/jackgr/following{/other_user}","gists_url":"https://api.github.com/users/jackgr/gists{/gist_id}","starred_url":"https://api.github.com/users/jackgr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jackgr/subscriptions","organizations_url":"https://api.github.com/users/jackgr/orgs","repos_url":"https://api.github.com/users/jackgr/repos","events_url":"https://api.github.com/users/jackgr/events{/privacy}","received_events_url":"https://api.github.com/users/jackgr/received_events","type":"User","site_admin":false},"body":"Fixed this issue a couple of commits ago. ","created_at":"2015-10-08T04:34:08Z","updated_at":"2015-10-08T04:34:08Z","html_url":"https://github.com/kubernetes/kubernetes/pull/13820#discussion_r41475438","pull_request_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/41475438"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/13820#discussion_r41475438"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820","id":44701510,"html_url":"https://github.com/kubernetes/kubernetes/pull/13820","diff_url":"https://github.com/kubernetes/kubernetes/pull/13820.diff","patch_url":"https://github.com/kubernetes/kubernetes/pull/13820.patch","issue_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/13820","number":13820,"state":"open","locked":false,"title":"Add method to apply strategic merge patch","user":{"login":"jackgr","id":5607565,"avatar_url":"https://avatars.githubusercontent.com/u/5607565?v=3","gravatar_id":"","url":"https://api.github.com/users/jackgr","html_url":"https://github.com/jackgr","followers_url":"https://api.github.com/users/jackgr/followers","following_url":"https://api.github.com/users/jackgr/following{/other_user}","gists_url":"https://api.github.com/users/jackgr/gists{/gist_id}","starred_url":"https://api.github.com/users/jackgr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jackgr/subscriptions","organizations_url":"https://api.github.com/users/jackgr/orgs","repos_url":"https://api.github.com/users/jackgr/repos","events_url":"https://api.github.com/users/jackgr/events{/privacy}","received_events_url":"https://api.github.com/users/jackgr/received_events","type":"User","site_admin":false},"body":"This PR builds on #13007 by adding a method to apply a strategic merge patch created by taking the difference between the original and modified user configuration and applying it to the current live configuration. This method detects and by default will automatically resolve conflicts in favor of the user. However, per discussion on #13007, we may want to add another method that applies the modified user configuration, plus delete directives relative to the original user configuration as the patch. Also, per discussion on #13576, we may want to revisit the question of conflict detection and resolution. Pending the development of any additional methods based on the outcome of those discussions, the method added by this PR can be used to do the equivalent of a git rebase -s theirs.","created_at":"2015-09-10T18:21:18Z","updated_at":"2015-10-08T04:34:08Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d9aa51b017b1543ff9bf9e17f86c55567828be9a","assignee":{"login":"jlowdermilk","id":2101035,"avatar_url":"https://avatars.githubusercontent.com/u/2101035?v=3","gravatar_id":"","url":"https://api.github.com/users/jlowdermilk","html_url":"https://github.com/jlowdermilk","followers_url":"https://api.github.com/users/jlowdermilk/followers","following_url":"https://api.github.com/users/jlowdermilk/following{/other_user}","gists_url":"https://api.github.com/users/jlowdermilk/gists{/gist_id}","starred_url":"https://api.github.com/users/jlowdermilk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jlowdermilk/subscriptions","organizations_url":"https://api.github.com/users/jlowdermilk/orgs","repos_url":"https://api.github.com/users/jlowdermilk/repos","events_url":"https://api.github.com/users/jlowdermilk/events{/privacy}","received_events_url":"https://api.github.com/users/jlowdermilk/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820/commits","review_comments_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820/comments","review_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/13820/comments","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/ddda379b1b20ef59a9699237ef36afc83f8fe39c","head":{"label":"jackgr:apply_patch","ref":"apply_patch","sha":"ddda379b1b20ef59a9699237ef36afc83f8fe39c","user":{"login":"jackgr","id":5607565,"avatar_url":"https://avatars.githubusercontent.com/u/5607565?v=3","gravatar_id":"","url":"https://api.github.com/users/jackgr","html_url":"https://github.com/jackgr","followers_url":"https://api.github.com/users/jackgr/followers","following_url":"https://api.github.com/users/jackgr/following{/other_user}","gists_url":"https://api.github.com/users/jackgr/gists{/gist_id}","starred_url":"https://api.github.com/users/jackgr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jackgr/subscriptions","organizations_url":"https://api.github.com/users/jackgr/orgs","repos_url":"https://api.github.com/users/jackgr/repos","events_url":"https://api.github.com/users/jackgr/events{/privacy}","received_events_url":"https://api.github.com/users/jackgr/received_events","type":"User","site_admin":false},"repo":{"id":28700637,"name":"kubernetes","full_name":"jackgr/kubernetes","owner":{"login":"jackgr","id":5607565,"avatar_url":"https://avatars.githubusercontent.com/u/5607565?v=3","gravatar_id":"","url":"https://api.github.com/users/jackgr","html_url":"https://github.com/jackgr","followers_url":"https://api.github.com/users/jackgr/followers","following_url":"https://api.github.com/users/jackgr/following{/other_user}","gists_url":"https://api.github.com/users/jackgr/gists{/gist_id}","starred_url":"https://api.github.com/users/jackgr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jackgr/subscriptions","organizations_url":"https://api.github.com/users/jackgr/orgs","repos_url":"https://api.github.com/users/jackgr/repos","events_url":"https://api.github.com/users/jackgr/events{/privacy}","received_events_url":"https://api.github.com/users/jackgr/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jackgr/kubernetes","description":"Container Cluster Manager","fork":true,"url":"https://api.github.com/repos/jackgr/kubernetes","forks_url":"https://api.github.com/repos/jackgr/kubernetes/forks","keys_url":"https://api.github.com/repos/jackgr/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jackgr/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jackgr/kubernetes/teams","hooks_url":"https://api.github.com/repos/jackgr/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/jackgr/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/jackgr/kubernetes/events","assignees_url":"https://api.github.com/repos/jackgr/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/jackgr/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/jackgr/kubernetes/tags","blobs_url":"https://api.github.com/repos/jackgr/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jackgr/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jackgr/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/jackgr/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jackgr/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/jackgr/kubernetes/languages","stargazers_url":"https://api.github.com/repos/jackgr/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/jackgr/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/jackgr/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/jackgr/kubernetes/subscription","commits_url":"https://api.github.com/repos/jackgr/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/jackgr/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/jackgr/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/jackgr/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/jackgr/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/jackgr/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jackgr/kubernetes/merges","archive_url":"https://api.github.com/repos/jackgr/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jackgr/kubernetes/downloads","issues_url":"https://api.github.com/repos/jackgr/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/jackgr/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/jackgr/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/jackgr/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jackgr/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/jackgr/kubernetes/releases{/id}","created_at":"2015-01-02T01:47:28Z","updated_at":"2015-09-14T04:42:45Z","pushed_at":"2015-10-08T00:18:05Z","git_url":"git://github.com/jackgr/kubernetes.git","ssh_url":"git@github.com:jackgr/kubernetes.git","clone_url":"https://github.com/jackgr/kubernetes.git","svn_url":"https://github.com/jackgr/kubernetes","homepage":null,"size":114342,"stargazers_count":1,"watchers_count":1,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"kubernetes:master","ref":"master","sha":"5bb53fbb4cfb0ca4bb72024744cdfaf3588d6b14","user":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"repo":{"id":20580498,"name":"kubernetes","full_name":"kubernetes/kubernetes","owner":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes/kubernetes","description":"Container Cluster Manager from Google","fork":false,"url":"https://api.github.com/repos/kubernetes/kubernetes","forks_url":"https://api.github.com/repos/kubernetes/kubernetes/forks","keys_url":"https://api.github.com/repos/kubernetes/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/kubernetes/teams","hooks_url":"https://api.github.com/repos/kubernetes/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/kubernetes/events","assignees_url":"https://api.github.com/repos/kubernetes/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/kubernetes/tags","blobs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/kubernetes/languages","stargazers_url":"https://api.github.com/repos/kubernetes/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/kubernetes/subscription","commits_url":"https://api.github.com/repos/kubernetes/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/kubernetes/merges","archive_url":"https://api.github.com/repos/kubernetes/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/kubernetes/downloads","issues_url":"https://api.github.com/repos/kubernetes/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/kubernetes/releases{/id}","created_at":"2014-06-06T22:56:04Z","updated_at":"2015-10-07T23:12:18Z","pushed_at":"2015-10-08T04:00:53Z","git_url":"git://github.com/kubernetes/kubernetes.git","ssh_url":"git@github.com:kubernetes/kubernetes.git","clone_url":"https://github.com/kubernetes/kubernetes.git","svn_url":"https://github.com/kubernetes/kubernetes","homepage":"http://kubernetes.io","size":446787,"stargazers_count":10595,"watchers_count":10595,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2661,"mirror_url":null,"open_issues_count":2025,"forks":2661,"open_issues":2025,"watchers":10595,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/13820"},"issue":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/13820"},"comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/13820/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/13820/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/kubernetes/statuses/ddda379b1b20ef59a9699237ef36afc83f8fe39c"}}}}