uffizzi-cli 0.6.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -7
  3. data/exe/uffizzi +1 -1
  4. data/lib/uffizzi/auth_helper.rb +0 -4
  5. data/lib/uffizzi/cli/common.rb +2 -2
  6. data/lib/uffizzi/cli/config.rb +5 -11
  7. data/lib/uffizzi/cli/connect.rb +74 -27
  8. data/lib/uffizzi/cli/disconnect.rb +1 -1
  9. data/lib/uffizzi/cli/login.rb +2 -2
  10. data/lib/uffizzi/cli/logout.rb +1 -1
  11. data/lib/uffizzi/cli/preview/service.rb +8 -7
  12. data/lib/uffizzi/cli/preview.rb +66 -123
  13. data/lib/uffizzi/cli/project/compose.rb +14 -16
  14. data/lib/uffizzi/cli/project/secret.rb +19 -8
  15. data/lib/uffizzi/cli/project.rb +31 -7
  16. data/lib/uffizzi/cli.rb +15 -23
  17. data/lib/uffizzi/clients/api/api_client.rb +66 -21
  18. data/lib/uffizzi/clients/api/api_routes.rb +8 -0
  19. data/lib/uffizzi/clients/api/http_client.rb +47 -45
  20. data/lib/uffizzi/date_helper.rb +45 -0
  21. data/lib/uffizzi/response_helper.rb +11 -7
  22. data/lib/uffizzi/services/command_service.rb +9 -0
  23. data/lib/uffizzi/services/compose_file_service.rb +3 -0
  24. data/lib/uffizzi/services/preview_service.rb +109 -0
  25. data/lib/uffizzi/version.rb +1 -1
  26. data/man/uffizzi-connect +37 -0
  27. data/man/uffizzi-connect-acr +35 -0
  28. data/man/uffizzi-connect-acr.ronn +28 -0
  29. data/man/uffizzi-connect-docker-hub +34 -0
  30. data/man/uffizzi-connect-docker-hub.ronn +27 -0
  31. data/man/uffizzi-connect-ecr +35 -0
  32. data/man/uffizzi-connect-ecr.ronn +28 -0
  33. data/man/uffizzi-connect-gcr +40 -0
  34. data/man/uffizzi-connect-gcr.ronn +32 -0
  35. data/man/uffizzi-connect-ghcr +35 -0
  36. data/man/uffizzi-connect-ghcr.ronn +28 -0
  37. data/man/uffizzi-connect.ronn +31 -0
  38. data/man/uffizzi-disconnect +37 -0
  39. data/man/uffizzi-disconnect.ronn +31 -0
  40. data/man/uffizzi-login +1 -1
  41. data/man/uffizzi-login.ronn +1 -1
  42. data/man/uffizzi-preview-update +34 -0
  43. data/man/uffizzi-preview-update.ronn +33 -0
  44. data/man/uffizzi-project-set-default +34 -0
  45. data/man/uffizzi-project-set-default.html +111 -0
  46. data/man/uffizzi-project-set-default.ronn +26 -0
  47. metadata +23 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de1f8c92c08b2d323c6c379bd5521aa394db91d85ed02ebc73f8c8457bb083d9
4
- data.tar.gz: 5c19dc240896c322b27d7dcf42499d6c5a67ce911ef3df625caf78fc71c259c5
3
+ metadata.gz: e9ab52c8638dc3d5a8f6245ba337da95fcf986e39040458add0c1128857014f8
4
+ data.tar.gz: b897ce235bc887bd161a7262fecddc28228b523b167338b599051ba370b704d3
5
5
  SHA512:
6
- metadata.gz: b653f34930cd546941d9646f7b5e2fccb854a784ed375e7da0b51f2a0cd9d9642b2463598ed6092e2d86be2de6ba804c9ae4c474290e5bdcee12123ad04fcd96
7
- data.tar.gz: 7f4c915af4bebe54b1ae2e96b2661d08374ce4d71a9fed04388b815bf3c6c6e02039bed214d8e6da678dc427d6753ac17869473a172df5c81bc5f2dca9c0c7c3
6
+ metadata.gz: a2976d6389a9a1d5c9d53ab66e34de98c391b250e2b4e5ebf636189b12f7e7a366e5140ef1c8583ce952d68fd8734600945402b6e38b10dea28700b71eb2bcf6
7
+ data.tar.gz: 78aa15c2dd0f21febc64c73c2a77e86de98ccda9a90278069ced243f3264f74240d5530aa67828515a4e03f858fb3e2d1d5d1713eca63127d027cbd4b3ea89ac
data/README.md CHANGED
@@ -4,14 +4,14 @@ A command-line interace (CLI) for [Uffizzi App](https://github.com/UffizziCloud/
4
4
 
5
5
  ## Uffizzi Overview
6
6
 
7
- Uffizzi is an open-source engine for creating lightweight, ephemeral test environments for APIs and full-stack applications. Uffizzi enables teams to preview new features before merging and to mitigate the risk of introducing regressions into a codebase. Each preview gets a shareable URL that's updated when you push new commits or image tags, so teams can provide continual feedback during the development/QA process. Previews can be configured to expire or be destroyed when a pull request is closed, so environments exist only as long as they are needed. Uffizzi also helps deconflict shared development environments since previews are deployed as isolated namespaces—there is no risk of clobbering another developer's preview.
7
+ Uffizzi is an open-source engine for creating lightweight, ephemeral test environments for APIs and full-stack applications. Uffizzi enables teams to preview new features before merging and to mitigate the risk of introducing regressions into a codebase. Each preview gets a shareable URL that's updated when you push new commits or image tags, so teams can provide continual feedback during the development/QA process. Previews can be configured to expire or be destroyed when a pull request is closed, so environments exist only as long as they are needed. Uffizzi also helps deconflict shared development environments since previews are deployed as isolated namespaces—there is no risk of clobbering another developer's preview.
8
8
 
9
9
  While Uffizzi depends on Kubernetes, it does not require end-users to interface with Kubernetes directly. Instead, Uffizzi leverages Docker Compose as its configuration file format, so developers do not need modify Kubernetes manifests or even know about Kubernetes.
10
10
 
11
11
  Uffizzi is designed to integrate with any CI/CD system.
12
12
 
13
13
  ## Uffizzi Architecture
14
- <img src="https://github.com/UffizziCloud/uffizzi_app/blob/main/docs/images/uffizzi-architecture.png" description="Uffizzi Architecture" width="320"/>
14
+ <img src="https://github.com/UffizziCloud/uffizzi_app/blob/main/docs/images/uffizzi-architecture.png" description="Uffizzi Architecture" width="320"/>
15
15
 
16
16
  Uffizzi consists of the following components:
17
17
 
@@ -31,7 +31,7 @@ The Uffizzi CLI can be used interactively or as part of an automated workflow (e
31
31
 
32
32
  ### Interactive mode
33
33
 
34
- Run the CLI as a Docker container in interactive mode:
34
+ Run the CLI as a Docker container in interactive mode:
35
35
  ```
36
36
  docker run --interactive --rm --tty --entrypoint=sh uffizzi/cli
37
37
  ```
@@ -44,9 +44,9 @@ entrypoint script can log you into Uffizzi before executing your command.
44
44
  - `UFFIZZI_PASSWORD`
45
45
  - `UFFIZZI_PROJECT` (optional)
46
46
 
47
- ### Automated mode
47
+ ### Automated mode
48
48
 
49
- If you want to use Uffizzi as part of an automated workflow, you can pass the Uffizzi commands to the Docker run command. For example:
49
+ If you want to use Uffizzi as part of an automated workflow, you can pass the Uffizzi commands to the Docker run command. For example:
50
50
 
51
51
  ```
52
52
  docker run -it --rm uffizzi/cli project list
@@ -141,7 +141,14 @@ uffizzi project list
141
141
 
142
142
  Shows all your projects' slugs
143
143
 
144
- If you have only one project it will be added to your config file automatically, if there's more than one project you need to set up your project manually with the command `uffizzi config set YOUR_PROJECT_SLUG`
144
+ If you have only one project it will be added to your config file automatically, if there's more than one project you need to set up your project manually with the commands `uffizzi config set YOUR_PROJECT_SLUG` or `uffizzi project set-default YOUR_PROJECT_SLUG`
145
+
146
+ ```
147
+ $ uffizzi project set-default PROJECT_SLUG
148
+ ```
149
+ Create a preview from a compose file.
150
+
151
+ Sets the default project given with the given project slug. When set, all commands use this project as the default context unless overridden by the --project flag.
145
152
 
146
153
  ### preview
147
154
 
@@ -169,4 +176,4 @@ Supported credential types - `docker-hub`, `acr`, `ecr`, `gcr`
169
176
 
170
177
  ## Contributing
171
178
 
172
- Bug reports and pull requests are welcome on GitHub at https://github.com/UffizziCloud/uffizzi_cli.
179
+ Bug reports and pull requests are welcome on GitHub at https://github.com/UffizziCloud/uffizzi_cli. See `CONTRIBUTING.md` in this repository.
data/exe/uffizzi CHANGED
@@ -2,4 +2,4 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'uffizzi/cli'
5
- Uffizzi::CLI.start
5
+ Uffizzi::Cli.start
@@ -9,10 +9,6 @@ module Uffizzi
9
9
  ConfigFile.option_has_value?(:cookie) &&
10
10
  ConfigFile.option_has_value?(:server)
11
11
  end
12
-
13
- def project_set?(options)
14
- !options[:project].nil? || (ConfigFile.exists? && ConfigFile.option_has_value?(:project))
15
- end
16
12
  end
17
13
  end
18
14
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'open3'
4
4
 
5
- module Cli
6
- class Common
5
+ module Uffizzi
6
+ class Cli::Common
7
7
  class << self
8
8
  def show_manual(command_name)
9
9
  manual_doc_path = File.join(Uffizzi.root, "man/#{command_name}")
@@ -4,31 +4,25 @@ require 'uffizzi'
4
4
  require 'uffizzi/clients/api/api_client'
5
5
 
6
6
  module Uffizzi
7
- class CLI::Config < Thor
7
+ class Cli::Config < Thor
8
8
  include ApiClient
9
9
 
10
- class << self
11
- def help(_shell, _subcommand)
12
- Cli::Common.show_manual(:config)
13
- end
14
- end
15
-
16
- desc 'list', 'list'
10
+ desc 'list', 'Lists all options and their values from the config file'
17
11
  def list
18
12
  run('list')
19
13
  end
20
14
 
21
- desc 'get [PROPERTY]', 'get'
15
+ desc 'get [PROPERTY]', 'Displays the value of the specified option'
22
16
  def get_value(property)
23
17
  run('get', property)
24
18
  end
25
19
 
26
- desc 'set [PROPERTY] [VALUE]', 'set'
20
+ desc 'set [PROPERTY] [VALUE]', 'Sets the value of the specified option'
27
21
  def set(property, value)
28
22
  run('set', property, value)
29
23
  end
30
24
 
31
- desc 'unset [PROPERTY]', 'unset'
25
+ desc 'unset [PROPERTY]', 'Deletes the value of the specified option'
32
26
  def unset(property)
33
27
  run('unset', property)
34
28
  end
@@ -3,29 +3,25 @@
3
3
  require 'uffizzi'
4
4
 
5
5
  module Uffizzi
6
- class CLI::Connect
6
+ class Cli::Connect < Thor
7
7
  include ApiClient
8
8
 
9
- def run(credential_type, credential_file_path)
10
- case credential_type
11
- when 'docker-hub'
12
- handle_docker_hub
13
- when 'acr'
14
- handle_azure
15
- when 'ecr'
16
- handle_amazon
17
- when 'ghcr'
18
- handle_github_container_registry
19
- when 'gcr'
20
- handle_google(credential_file_path)
9
+ desc 'list-credentials', 'List existing credentials for an account'
10
+ def list_credentials
11
+ server = ConfigFile.read_option(:server)
12
+ response = fetch_credentials(server)
13
+ if ResponseHelper.ok?(response)
14
+ handle_list_credentials_success(response)
21
15
  else
22
- Uffizzi.ui.say('Unsupported credential type.')
16
+ ResponseHelper.handle_failed_response(response)
23
17
  end
24
18
  end
25
19
 
26
- private
20
+ desc 'docker-hub', 'Connect to Docker Hub (hub.docker.com)'
21
+ def docker_hub
22
+ type = Uffizzi.configuration.credential_types[:dockerhub]
23
+ check_credential_existance(type, 'docker-hub')
27
24
 
28
- def handle_docker_hub
29
25
  username = Uffizzi.ui.ask('Username: ')
30
26
  password = Uffizzi.ui.ask('Password: ', echo: false)
31
27
 
@@ -45,7 +41,11 @@ module Uffizzi
45
41
  end
46
42
  end
47
43
 
48
- def handle_azure
44
+ desc 'acr', 'Connect to Azure Container Registry (azurecr.io)'
45
+ def acr
46
+ type = Uffizzi.configuration.credential_types[:azure]
47
+ check_credential_existance(type, 'acr')
48
+
49
49
  registry_url = prepare_registry_url(Uffizzi.ui.ask('Registry Domain: '))
50
50
  username = Uffizzi.ui.ask('Docker ID: ')
51
51
  password = Uffizzi.ui.ask('Password/Access Token: ', echo: false)
@@ -54,7 +54,7 @@ module Uffizzi
54
54
  username: username,
55
55
  password: password,
56
56
  registry_url: registry_url,
57
- type: Uffizzi.configuration.credential_types[:azure],
57
+ type: type,
58
58
  }
59
59
 
60
60
  server = ConfigFile.read_option(:server)
@@ -67,7 +67,11 @@ module Uffizzi
67
67
  end
68
68
  end
69
69
 
70
- def handle_amazon
70
+ desc 'ecr', 'Connect to Amazon Elastic Container Registry'
71
+ def ecr
72
+ type = Uffizzi.configuration.credential_types[:amazon]
73
+ check_credential_existance(type, 'ecr')
74
+
71
75
  registry_url = prepare_registry_url(Uffizzi.ui.ask('Registry Domain: '))
72
76
  username = Uffizzi.ui.ask('Access key ID: ')
73
77
  password = Uffizzi.ui.ask('Secret access key: ', echo: false)
@@ -76,7 +80,7 @@ module Uffizzi
76
80
  username: username,
77
81
  password: password,
78
82
  registry_url: registry_url,
79
- type: Uffizzi.configuration.credential_types[:amazon],
83
+ type: type,
80
84
  }
81
85
 
82
86
  server = ConfigFile.read_option(:server)
@@ -89,7 +93,11 @@ module Uffizzi
89
93
  end
90
94
  end
91
95
 
92
- def handle_google(credential_file_path)
96
+ desc 'gcr', 'Connect to Google Container Registry (gcr.io)'
97
+ def gcr(credential_file_path = nil)
98
+ type = Uffizzi.configuration.credential_types[:google]
99
+ check_credential_existance(type, 'gcr')
100
+
93
101
  return Uffizzi.ui.say('Path to google service account key file wasn\'t specified.') if credential_file_path.nil?
94
102
 
95
103
  begin
@@ -100,7 +108,7 @@ module Uffizzi
100
108
 
101
109
  params = {
102
110
  password: credential_content,
103
- type: Uffizzi.configuration.credential_types[:google],
111
+ type: type,
104
112
  }
105
113
 
106
114
  server = ConfigFile.read_option(:server)
@@ -113,26 +121,35 @@ module Uffizzi
113
121
  end
114
122
  end
115
123
 
116
- def handle_github_container_registry
124
+ desc 'ghcr', 'Connect to GitHub Container Registry (ghcr.io)'
125
+ def ghcr
126
+ type = Uffizzi.configuration.credential_types[:github_container_registry]
127
+ check_credential_existance(type, 'gchr')
128
+
117
129
  username = Uffizzi.ui.ask('Github Username: ')
118
130
  password = Uffizzi.ui.ask('Access Token: ', echo: false)
119
131
 
120
132
  params = {
121
133
  username: username,
122
134
  password: password,
123
- type: Uffizzi.configuration.credential_types[:github_container_registry],
135
+ type: type,
124
136
  }
125
137
 
126
- hostname = ConfigFile.read_option(:hostname)
127
- response = create_credential(hostname, params)
138
+ server = ConfigFile.read_option(:server)
139
+ response = create_credential(server, params)
128
140
 
129
141
  if ResponseHelper.created?(response)
130
- print_success_message('GitHub Container Registry')
142
+ print_success_message('GHCR')
131
143
  else
132
144
  ResponseHelper.handle_failed_response(response)
133
145
  end
134
146
  end
135
147
 
148
+ map 'list-credentials' => 'list_credentials'
149
+ map 'docker-hub' => 'docker_hub'
150
+
151
+ private
152
+
136
153
  def prepare_registry_url(registry_url)
137
154
  return registry_url if registry_url.match?(/^(?:http(s)?:\/\/)/)
138
155
 
@@ -142,5 +159,35 @@ module Uffizzi
142
159
  def print_success_message(connection_name)
143
160
  Uffizzi.ui.say("Successfully connected to #{connection_name}")
144
161
  end
162
+
163
+ def check_credential_existance(type, connection_name)
164
+ server = ConfigFile.read_option(:server)
165
+ response = check_credential(server, type)
166
+ return if ResponseHelper.ok?(response)
167
+
168
+ message = "Credentials of type #{connection_name} already exist for this account. " \
169
+ "To remove them, run $ uffizzi disconnect #{connection_name}."
170
+ raise Uffizzi::Error.new(message)
171
+ end
172
+
173
+ def handle_list_credentials_success(response)
174
+ credentials = response[:body][:credentials]
175
+ credentials.each do |credential|
176
+ Uffizzi.ui.say(credential_readable_name(credential))
177
+ end
178
+ end
179
+
180
+ def credential_readable_name(credential)
181
+ map = {
182
+ 'UffizziCore::Credential::DockerHub' => 'docker-hub',
183
+ 'UffizziCore::Credential::Github' => 'github',
184
+ 'UffizziCore::Credential::Azure' => 'acr',
185
+ 'UffizziCore::Credential::Amazon' => 'ecr',
186
+ 'UffizziCore::Credential::GithubContainerRegistry' => 'ghcr',
187
+ 'UffizziCore::Credential::Google' => 'gcr',
188
+ }
189
+
190
+ map[credential]
191
+ end
145
192
  end
146
193
  end
@@ -3,7 +3,7 @@
3
3
  require 'uffizzi'
4
4
 
5
5
  module Uffizzi
6
- class CLI::Disconnect
6
+ class Cli::Disconnect
7
7
  include ApiClient
8
8
 
9
9
  def run(credential_type)
@@ -5,7 +5,7 @@ require 'uffizzi/response_helper'
5
5
  require 'uffizzi/clients/api/api_client'
6
6
 
7
7
  module Uffizzi
8
- class CLI::Login
8
+ class Cli::Login
9
9
  include ApiClient
10
10
 
11
11
  def initialize(options)
@@ -13,7 +13,7 @@ module Uffizzi
13
13
  end
14
14
 
15
15
  def run
16
- Uffizzi.ui.say('Login to Uffizzi to your previews.')
16
+ Uffizzi.ui.say('Login to Uffizzi to view and manage your previews.')
17
17
  server = set_server
18
18
  username = set_username
19
19
  password = set_password
@@ -4,7 +4,7 @@ require 'uffizzi'
4
4
  require 'uffizzi/auth_helper'
5
5
 
6
6
  module Uffizzi
7
- class CLI::Logout
7
+ class Cli::Logout
8
8
  include ApiClient
9
9
 
10
10
  def initialize(options)
@@ -4,15 +4,16 @@ require 'uffizzi'
4
4
  require 'uffizzi/auth_helper'
5
5
  require 'uffizzi/response_helper'
6
6
  require 'uffizzi/services/preview_service'
7
+ require 'uffizzi/services/command_service'
7
8
 
8
9
  module Uffizzi
9
- class CLI::Preview::Service < Thor
10
+ class Cli::Preview::Service < Thor
10
11
  include ApiClient
11
12
 
12
- desc 'logs [LOGS_TYPE] [DEPLOYMENT_ID] [CONTAINER_NAME]', 'logs'
13
+ desc 'logs [LOGS_TYPE] [DEPLOYMENT_ID] [CONTAINER_NAME]', 'Show the logs for a container service of a preview'
13
14
  def logs(logs_type, deployment_name, container_name = args)
14
15
  return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
15
- return Uffizzi.ui.say('This command needs project to be set in config file') unless Uffizzi::AuthHelper.project_set?(options)
16
+ return Uffizzi.ui.say('This command needs project to be set in config file') unless CommandService.project_set?(options)
16
17
 
17
18
  deployment_id = PreviewService.read_deployment_id(deployment_name)
18
19
  response = service_logs_response(logs_type, deployment_id, container_name)
@@ -25,12 +26,12 @@ module Uffizzi
25
26
  end
26
27
  end
27
28
 
28
- desc 'logs [DEPLOYMENT_ID]', 'list'
29
+ desc 'list [DEPLOYMENT_ID]', 'List the container services of a given preview'
29
30
  def list(deployment_name)
30
31
  return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
31
- return Uffizzi.ui.say('This command needs project to be set in config file') unless Uffizzi::AuthHelper.project_set?(options)
32
+ return Uffizzi.ui.say('This command needs project to be set in config file') unless CommandService.project_set?(options)
32
33
 
33
- project_slug = ConfigFile.read_option(:project)
34
+ project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
34
35
  server = ConfigFile.read_option(:server)
35
36
  deployment_id = PreviewService.read_deployment_id(deployment_name)
36
37
  response = fetch_deployment_services(server, project_slug, deployment_id)
@@ -45,7 +46,7 @@ module Uffizzi
45
46
  private
46
47
 
47
48
  def service_logs_response(logs_type, deployment_id, container_name)
48
- project_slug = ConfigFile.read_option(:project)
49
+ project_slug = options[:project].nil? ? ConfigFile.read_option(:project) : options[:project]
49
50
  server = ConfigFile.read_option(:server)
50
51
 
51
52
  case logs_type