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.
- checksums.yaml +4 -4
- data/README.md +14 -7
- data/exe/uffizzi +1 -1
- data/lib/uffizzi/auth_helper.rb +0 -4
- data/lib/uffizzi/cli/common.rb +2 -2
- data/lib/uffizzi/cli/config.rb +5 -11
- data/lib/uffizzi/cli/connect.rb +74 -27
- data/lib/uffizzi/cli/disconnect.rb +1 -1
- data/lib/uffizzi/cli/login.rb +2 -2
- data/lib/uffizzi/cli/logout.rb +1 -1
- data/lib/uffizzi/cli/preview/service.rb +8 -7
- data/lib/uffizzi/cli/preview.rb +66 -123
- data/lib/uffizzi/cli/project/compose.rb +14 -16
- data/lib/uffizzi/cli/project/secret.rb +19 -8
- data/lib/uffizzi/cli/project.rb +31 -7
- data/lib/uffizzi/cli.rb +15 -23
- data/lib/uffizzi/clients/api/api_client.rb +66 -21
- data/lib/uffizzi/clients/api/api_routes.rb +8 -0
- data/lib/uffizzi/clients/api/http_client.rb +47 -45
- data/lib/uffizzi/date_helper.rb +45 -0
- data/lib/uffizzi/response_helper.rb +11 -7
- data/lib/uffizzi/services/command_service.rb +9 -0
- data/lib/uffizzi/services/compose_file_service.rb +3 -0
- data/lib/uffizzi/services/preview_service.rb +109 -0
- data/lib/uffizzi/version.rb +1 -1
- data/man/uffizzi-connect +37 -0
- data/man/uffizzi-connect-acr +35 -0
- data/man/uffizzi-connect-acr.ronn +28 -0
- data/man/uffizzi-connect-docker-hub +34 -0
- data/man/uffizzi-connect-docker-hub.ronn +27 -0
- data/man/uffizzi-connect-ecr +35 -0
- data/man/uffizzi-connect-ecr.ronn +28 -0
- data/man/uffizzi-connect-gcr +40 -0
- data/man/uffizzi-connect-gcr.ronn +32 -0
- data/man/uffizzi-connect-ghcr +35 -0
- data/man/uffizzi-connect-ghcr.ronn +28 -0
- data/man/uffizzi-connect.ronn +31 -0
- data/man/uffizzi-disconnect +37 -0
- data/man/uffizzi-disconnect.ronn +31 -0
- data/man/uffizzi-login +1 -1
- data/man/uffizzi-login.ronn +1 -1
- data/man/uffizzi-preview-update +34 -0
- data/man/uffizzi-preview-update.ronn +33 -0
- data/man/uffizzi-project-set-default +34 -0
- data/man/uffizzi-project-set-default.html +111 -0
- data/man/uffizzi-project-set-default.ronn +26 -0
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9ab52c8638dc3d5a8f6245ba337da95fcf986e39040458add0c1128857014f8
|
4
|
+
data.tar.gz: b897ce235bc887bd161a7262fecddc28228b523b167338b599051ba370b704d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
data/lib/uffizzi/auth_helper.rb
CHANGED
@@ -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
|
data/lib/uffizzi/cli/common.rb
CHANGED
data/lib/uffizzi/cli/config.rb
CHANGED
@@ -4,31 +4,25 @@ require 'uffizzi'
|
|
4
4
|
require 'uffizzi/clients/api/api_client'
|
5
5
|
|
6
6
|
module Uffizzi
|
7
|
-
class
|
7
|
+
class Cli::Config < Thor
|
8
8
|
include ApiClient
|
9
9
|
|
10
|
-
|
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]', '
|
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]', '
|
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]', '
|
25
|
+
desc 'unset [PROPERTY]', 'Deletes the value of the specified option'
|
32
26
|
def unset(property)
|
33
27
|
run('unset', property)
|
34
28
|
end
|
data/lib/uffizzi/cli/connect.rb
CHANGED
@@ -3,29 +3,25 @@
|
|
3
3
|
require 'uffizzi'
|
4
4
|
|
5
5
|
module Uffizzi
|
6
|
-
class
|
6
|
+
class Cli::Connect < Thor
|
7
7
|
include ApiClient
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
16
|
+
ResponseHelper.handle_failed_response(response)
|
23
17
|
end
|
24
18
|
end
|
25
19
|
|
26
|
-
|
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
|
-
|
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:
|
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
|
-
|
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:
|
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
|
-
|
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:
|
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
|
-
|
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:
|
135
|
+
type: type,
|
124
136
|
}
|
125
137
|
|
126
|
-
|
127
|
-
response = create_credential(
|
138
|
+
server = ConfigFile.read_option(:server)
|
139
|
+
response = create_credential(server, params)
|
128
140
|
|
129
141
|
if ResponseHelper.created?(response)
|
130
|
-
print_success_message('
|
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
|
data/lib/uffizzi/cli/login.rb
CHANGED
@@ -5,7 +5,7 @@ require 'uffizzi/response_helper'
|
|
5
5
|
require 'uffizzi/clients/api/api_client'
|
6
6
|
|
7
7
|
module Uffizzi
|
8
|
-
class
|
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
|
data/lib/uffizzi/cli/logout.rb
CHANGED
@@ -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
|
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
|
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 '
|
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
|
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
|