{"action":"created","comment":{"url":"https://api.github.com/repos/openshift/origin/pulls/comments/29357281","id":29357281,"diff_hunk":"@@ -0,0 +1,181 @@\n+package cmd\n+\n+import (\n+\t\"fmt\"\n+\t\"io\"\n+\n+\t\"github.com/spf13/cobra\"\n+\n+\tkapi \"github.com/GoogleCloudPlatform/kubernetes/pkg/api\"\n+\tkerrors \"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors\"\n+\tcmdutil \"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util\"\n+\n+\t\"github.com/openshift/origin/pkg/cmd/cli/describe\"\n+\t\"github.com/openshift/origin/pkg/cmd/util/clientcmd\"\n+\tdeployapi \"github.com/openshift/origin/pkg/deploy/api\"\n+\tdeployutil \"github.com/openshift/origin/pkg/deploy/util\"\n+)\n+\n+const newCmdDeployDescription = `\n+View, start and restart deployments.\n+\n+If no options are given, view the latest deployment.\n+\n+NOTE: This command is still under active development and is subject to change.\n+`\n+\n+// NewCmdDeploy creates a new `deploy` command.\n+func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {\n+\tvar deployLatest bool\n+\tvar retryDeploy bool\n+\n+\tcmd := &cobra.Command{\n+\t\tUse:   \"deploy <deploymentConfig>\",\n+\t\tShort: \"View, start and restart deployments.\",\n+\t\tLong:  newCmdDeployDescription,\n+\t\tRun: func(cmd *cobra.Command, args []string) {\n+\t\t\tif len(args) == 0 || len(args[0]) == 0 {\n+\t\t\t\tfmt.Println(cmdutil.UsageError(cmd, \"A deploymentConfig name is required.\"))\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t\tif deployLatest && retryDeploy {\n+\t\t\t\tfmt.Println(cmdutil.UsageError(cmd, \"Only one of --latest or --retry is allowed.\"))\n+\t\t\t\treturn\n+\t\t\t}\n+\n+\t\t\tconfigName := args[0]\n+\n+\t\t\tosClient, kubeClient, err := f.Clients()\n+\t\t\tcmdutil.CheckErr(err)\n+\n+\t\t\tnamespace, err := f.DefaultNamespace()\n+\t\t\tcmdutil.CheckErr(err)\n+\n+\t\t\tconfig, err := osClient.DeploymentConfigs(namespace).Get(configName)\n+\t\t\tcmdutil.CheckErr(err)\n+\n+\t\t\tcommandClient := &deployCommandClientImpl{\n+\t\t\t\tGetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) {\n+\t\t\t\t\treturn kubeClient.ReplicationControllers(namespace).Get(name)\n+\t\t\t\t},\n+\t\t\t\tUpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {\n+\t\t\t\t\treturn osClient.DeploymentConfigs(config.Namespace).Update(config)\n+\t\t\t\t},\n+\t\t\t\tUpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {\n+\t\t\t\t\treturn kubeClient.ReplicationControllers(deployment.Namespace).Update(deployment)\n+\t\t\t\t},\n+\t\t\t}\n+\n+\t\t\tswitch {\n+\t\t\tcase deployLatest:\n+\t\t\t\tc := &deployLatestCommand{client: commandClient}\n+\t\t\t\terr = c.deploy(config, out)\n+\t\t\tcase retryDeploy:\n+\t\t\t\tc := &retryDeploymentCommand{client: commandClient}\n+\t\t\t\terr = c.retry(config, out)\n+\t\t\tdefault:\n+\t\t\t\tdescriber := describe.NewLatestDeploymentDescriber(osClient, kubeClient)\n+\t\t\t\tdesc, err := describer.Describe(config.Namespace, config.Name)\n+\t\t\t\tcmdutil.CheckErr(err)\n+\t\t\t\tfmt.Fprintln(out, desc)\n+\t\t\t}\n+\t\t\tcmdutil.CheckErr(err)\n+\t\t},\n+\t}\n+\n+\tcmd.Flags().BoolVar(&deployLatest, \"latest\", false, \"Start a new deployment now.\")\n+\tcmd.Flags().BoolVar(&retryDeploy, \"retry\", false, \"Retry the latest failed deployment.\")\n+\n+\treturn cmd\n+}\n+\n+// deployCommandClient abstracts access to the API server.\n+type deployCommandClient interface {\n+\tGetDeployment(namespace, name string) (*kapi.ReplicationController, error)\n+\tUpdateDeploymentConfig(*deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error)\n+\tUpdateDeployment(*kapi.ReplicationController) (*kapi.ReplicationController, error)\n+}\n+\n+// deployLatestCommand can launch new deployments.\n+type deployLatestCommand struct {\n+\tclient deployCommandClient\n+}\n+\n+// deploy launches a new deployment unless there's already a deployment\n+// process in progress for config.\n+func (c *deployLatestCommand) deploy(config *deployapi.DeploymentConfig, out io.Writer) error {\n+\tdeploymentName := deployutil.LatestDeploymentNameForConfig(config)\n+\tdeployment, err := c.client.GetDeployment(config.Namespace, deploymentName)\n+\tif err != nil {\n+\t\tif !kerrors.IsNotFound(err) {\n+\t\t\treturn err\n+\t\t}\n+\t} else {\n+\t\t// Reject attempts to start a concurrent deployment.\n+\t\tstatus := statusFor(deployment)\n+\t\tif status != deployapi.DeploymentStatusComplete && status != deployapi.DeploymentStatusFailed {\n+\t\t\treturn fmt.Errorf(\"#%d is already in progress (%s)\", config.LatestVersion, status)\n+\t\t}\n+\t}\n+\n+\tconfig.LatestVersion++\n+\t_, err = c.client.UpdateDeploymentConfig(config)\n+\tif err == nil {\n+\t\tfmt.Fprintf(out, \"deployed #%d\\n\", config.LatestVersion)\n+\t}\n+\treturn err\n+}\n+\n+// retryDeploymentCommand can retry failed deployments.\n+type retryDeploymentCommand struct {\n+\tclient deployCommandClient\n+}\n+\n+// retry resets the status of the latest deployment to New, which will cause\n+// the deployment to be retried. An error is returned if the deployment is not\n+// currently in a failed state.\n+func (c *retryDeploymentCommand) retry(config *deployapi.DeploymentConfig, out io.Writer) error {\n+\tif config.LatestVersion == 0 {\n+\t\treturn fmt.Errorf(\"no failed deployments found for %s/%s\", config.Namespace, config.Name)\n+\t}\n+\tdeploymentName := deployutil.LatestDeploymentNameForConfig(config)\n+\tdeployment, err := c.client.GetDeployment(config.Namespace, deploymentName)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tstatus := statusFor(deployment)\n+\n+\tif status != deployapi.DeploymentStatusFailed {\n+\t\treturn fmt.Errorf(\"#%d is %s; only failed deployments can be retried\", config.LatestVersion, status)\n+\t}\n+\n+\tdeployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusNew)\n+\t_, err = c.client.UpdateDeployment(deployment)\n+\tif err == nil {\n+\t\tfmt.Fprintf(out, \"retried #%d\\n\", config.LatestVersion)\n+\t}\n+\treturn err\n+}\n+\n+func statusFor(deployment *kapi.ReplicationController) deployapi.DeploymentStatus {\n+\treturn deployapi.DeploymentStatus(deployment.Annotations[deployapi.DeploymentStatusAnnotation])\n+}\n+\n+// deployCommandClientImpl is a pluggable deployCommandClient.\n+type deployCommandClientImpl struct {","path":"pkg/cmd/cli/cmd/deploy.go","position":166,"original_position":166,"commit_id":"349e59a9448032f3d32ffe6deed3501e5a82cb48","original_commit_id":"349e59a9448032f3d32ffe6deed3501e5a82cb48","user":{"login":"smarterclayton","id":1163175,"avatar_url":"https://avatars.githubusercontent.com/u/1163175?v=3","gravatar_id":"","url":"https://api.github.com/users/smarterclayton","html_url":"https://github.com/smarterclayton","followers_url":"https://api.github.com/users/smarterclayton/followers","following_url":"https://api.github.com/users/smarterclayton/following{/other_user}","gists_url":"https://api.github.com/users/smarterclayton/gists{/gist_id}","starred_url":"https://api.github.com/users/smarterclayton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smarterclayton/subscriptions","organizations_url":"https://api.github.com/users/smarterclayton/orgs","repos_url":"https://api.github.com/users/smarterclayton/repos","events_url":"https://api.github.com/users/smarterclayton/events{/privacy}","received_events_url":"https://api.github.com/users/smarterclayton/received_events","type":"User","site_admin":false},"body":"This abstraction is a bit much (you should just take DeploymentConfigNamespacer instead)","created_at":"2015-04-29T17:09:48Z","updated_at":"2015-04-29T17:09:48Z","html_url":"https://github.com/openshift/origin/pull/1947#discussion_r29357281","pull_request_url":"https://api.github.com/repos/openshift/origin/pulls/1947","_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments/29357281"},"html":{"href":"https://github.com/openshift/origin/pull/1947#discussion_r29357281"},"pull_request":{"href":"https://api.github.com/repos/openshift/origin/pulls/1947"}}},"pull_request":{"url":"https://api.github.com/repos/openshift/origin/pulls/1947","id":34269455,"html_url":"https://github.com/openshift/origin/pull/1947","diff_url":"https://github.com/openshift/origin/pull/1947.diff","patch_url":"https://github.com/openshift/origin/pull/1947.patch","issue_url":"https://api.github.com/repos/openshift/origin/issues/1947","number":1947,"state":"open","locked":false,"title":"Add a deploy command","user":{"login":"ironcladlou","id":298299,"avatar_url":"https://avatars.githubusercontent.com/u/298299?v=3","gravatar_id":"","url":"https://api.github.com/users/ironcladlou","html_url":"https://github.com/ironcladlou","followers_url":"https://api.github.com/users/ironcladlou/followers","following_url":"https://api.github.com/users/ironcladlou/following{/other_user}","gists_url":"https://api.github.com/users/ironcladlou/gists{/gist_id}","starred_url":"https://api.github.com/users/ironcladlou/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ironcladlou/subscriptions","organizations_url":"https://api.github.com/users/ironcladlou/orgs","repos_url":"https://api.github.com/users/ironcladlou/repos","events_url":"https://api.github.com/users/ironcladlou/events{/privacy}","received_events_url":"https://api.github.com/users/ironcladlou/received_events","type":"User","site_admin":false},"body":"Add a deploy command which allows users to view, start, and restart\r\ndeployments manually.","created_at":"2015-04-28T14:01:23Z","updated_at":"2015-04-29T17:09:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cc4b045f3458b63dd193df3f22eb0dd1e7656697","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openshift/origin/pulls/1947/commits","review_comments_url":"https://api.github.com/repos/openshift/origin/pulls/1947/comments","review_comment_url":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openshift/origin/issues/1947/comments","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/349e59a9448032f3d32ffe6deed3501e5a82cb48","head":{"label":"ironcladlou:deploy-command","ref":"deploy-command","sha":"349e59a9448032f3d32ffe6deed3501e5a82cb48","user":{"login":"ironcladlou","id":298299,"avatar_url":"https://avatars.githubusercontent.com/u/298299?v=3","gravatar_id":"","url":"https://api.github.com/users/ironcladlou","html_url":"https://github.com/ironcladlou","followers_url":"https://api.github.com/users/ironcladlou/followers","following_url":"https://api.github.com/users/ironcladlou/following{/other_user}","gists_url":"https://api.github.com/users/ironcladlou/gists{/gist_id}","starred_url":"https://api.github.com/users/ironcladlou/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ironcladlou/subscriptions","organizations_url":"https://api.github.com/users/ironcladlou/orgs","repos_url":"https://api.github.com/users/ironcladlou/repos","events_url":"https://api.github.com/users/ironcladlou/events{/privacy}","received_events_url":"https://api.github.com/users/ironcladlou/received_events","type":"User","site_admin":false},"repo":{"id":23721352,"name":"origin","full_name":"ironcladlou/origin","owner":{"login":"ironcladlou","id":298299,"avatar_url":"https://avatars.githubusercontent.com/u/298299?v=3","gravatar_id":"","url":"https://api.github.com/users/ironcladlou","html_url":"https://github.com/ironcladlou","followers_url":"https://api.github.com/users/ironcladlou/followers","following_url":"https://api.github.com/users/ironcladlou/following{/other_user}","gists_url":"https://api.github.com/users/ironcladlou/gists{/gist_id}","starred_url":"https://api.github.com/users/ironcladlou/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ironcladlou/subscriptions","organizations_url":"https://api.github.com/users/ironcladlou/orgs","repos_url":"https://api.github.com/users/ironcladlou/repos","events_url":"https://api.github.com/users/ironcladlou/events{/privacy}","received_events_url":"https://api.github.com/users/ironcladlou/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ironcladlou/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":true,"url":"https://api.github.com/repos/ironcladlou/origin","forks_url":"https://api.github.com/repos/ironcladlou/origin/forks","keys_url":"https://api.github.com/repos/ironcladlou/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ironcladlou/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ironcladlou/origin/teams","hooks_url":"https://api.github.com/repos/ironcladlou/origin/hooks","issue_events_url":"https://api.github.com/repos/ironcladlou/origin/issues/events{/number}","events_url":"https://api.github.com/repos/ironcladlou/origin/events","assignees_url":"https://api.github.com/repos/ironcladlou/origin/assignees{/user}","branches_url":"https://api.github.com/repos/ironcladlou/origin/branches{/branch}","tags_url":"https://api.github.com/repos/ironcladlou/origin/tags","blobs_url":"https://api.github.com/repos/ironcladlou/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ironcladlou/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ironcladlou/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/ironcladlou/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ironcladlou/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/ironcladlou/origin/languages","stargazers_url":"https://api.github.com/repos/ironcladlou/origin/stargazers","contributors_url":"https://api.github.com/repos/ironcladlou/origin/contributors","subscribers_url":"https://api.github.com/repos/ironcladlou/origin/subscribers","subscription_url":"https://api.github.com/repos/ironcladlou/origin/subscription","commits_url":"https://api.github.com/repos/ironcladlou/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/ironcladlou/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/ironcladlou/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/ironcladlou/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/ironcladlou/origin/contents/{+path}","compare_url":"https://api.github.com/repos/ironcladlou/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ironcladlou/origin/merges","archive_url":"https://api.github.com/repos/ironcladlou/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ironcladlou/origin/downloads","issues_url":"https://api.github.com/repos/ironcladlou/origin/issues{/number}","pulls_url":"https://api.github.com/repos/ironcladlou/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/ironcladlou/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/ironcladlou/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ironcladlou/origin/labels{/name}","releases_url":"https://api.github.com/repos/ironcladlou/origin/releases{/id}","created_at":"2014-09-05T23:22:09Z","updated_at":"2015-04-29T15:08:27Z","pushed_at":"2015-04-29T17:00:03Z","git_url":"git://github.com/ironcladlou/origin.git","ssh_url":"git@github.com:ironcladlou/origin.git","clone_url":"https://github.com/ironcladlou/origin.git","svn_url":"https://github.com/ironcladlou/origin","homepage":"https://openshift.github.io","size":102478,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"openshift:master","ref":"master","sha":"59012cdc13b011859c4f939ba3748d28eddef7aa","user":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"repo":{"id":22442668,"name":"origin","full_name":"openshift/origin","owner":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openshift/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":false,"url":"https://api.github.com/repos/openshift/origin","forks_url":"https://api.github.com/repos/openshift/origin/forks","keys_url":"https://api.github.com/repos/openshift/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openshift/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openshift/origin/teams","hooks_url":"https://api.github.com/repos/openshift/origin/hooks","issue_events_url":"https://api.github.com/repos/openshift/origin/issues/events{/number}","events_url":"https://api.github.com/repos/openshift/origin/events","assignees_url":"https://api.github.com/repos/openshift/origin/assignees{/user}","branches_url":"https://api.github.com/repos/openshift/origin/branches{/branch}","tags_url":"https://api.github.com/repos/openshift/origin/tags","blobs_url":"https://api.github.com/repos/openshift/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openshift/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openshift/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/openshift/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/openshift/origin/languages","stargazers_url":"https://api.github.com/repos/openshift/origin/stargazers","contributors_url":"https://api.github.com/repos/openshift/origin/contributors","subscribers_url":"https://api.github.com/repos/openshift/origin/subscribers","subscription_url":"https://api.github.com/repos/openshift/origin/subscription","commits_url":"https://api.github.com/repos/openshift/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/openshift/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/openshift/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/openshift/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/openshift/origin/contents/{+path}","compare_url":"https://api.github.com/repos/openshift/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openshift/origin/merges","archive_url":"https://api.github.com/repos/openshift/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openshift/origin/downloads","issues_url":"https://api.github.com/repos/openshift/origin/issues{/number}","pulls_url":"https://api.github.com/repos/openshift/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/openshift/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/openshift/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openshift/origin/labels{/name}","releases_url":"https://api.github.com/repos/openshift/origin/releases{/id}","created_at":"2014-07-30T20:04:05Z","updated_at":"2015-04-29T17:05:16Z","pushed_at":"2015-04-29T17:00:04Z","git_url":"git://github.com/openshift/origin.git","ssh_url":"git@github.com:openshift/origin.git","clone_url":"https://github.com/openshift/origin.git","svn_url":"https://github.com/openshift/origin","homepage":"http://www.openshift.org","size":164723,"stargazers_count":392,"watchers_count":392,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":196,"mirror_url":null,"open_issues_count":250,"forks":196,"open_issues":250,"watchers":392,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/1947"},"html":{"href":"https://github.com/openshift/origin/pull/1947"},"issue":{"href":"https://api.github.com/repos/openshift/origin/issues/1947"},"comments":{"href":"https://api.github.com/repos/openshift/origin/issues/1947/comments"},"review_comments":{"href":"https://api.github.com/repos/openshift/origin/pulls/1947/comments"},"review_comment":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openshift/origin/pulls/1947/commits"},"statuses":{"href":"https://api.github.com/repos/openshift/origin/statuses/349e59a9448032f3d32ffe6deed3501e5a82cb48"}}}}