uffizzi-cli 0.2.2 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2edd95fc4165e75f533b8925b92031b83baa0db249e78234df4afff63ac1f509
4
- data.tar.gz: 856ce13ac1dbf34a84f8304456c3226286825a2626661e69ded2953e12fa6438
3
+ metadata.gz: 6fc16d251381e8a47bfe848848cb61b39216ac90ec0d5ccf0a7ff509c2003dab
4
+ data.tar.gz: 3f08d714a939b22f151d4ac47f79d9b24ee0ec3092aec39b12211a6629dd9946
5
5
  SHA512:
6
- metadata.gz: 8ac95ad20cef50b6a72c0cc67c7faaf92135f054e32dd5f5aaa7436b4545459d057a7a93e12d720cec2b455ceac5c9603414034f496dc3bd4fc9e9b5a190ab4e
7
- data.tar.gz: 457220d0efead268142c44dcb4a9b6fe92b4f26428191618212ae133a46aad57087649061077341befcdf71d8025dd9ef99b48f228b7e4c0032eba2ba4a048e6
6
+ metadata.gz: 988b8c95ebb79d0e12387b0507a38187d9fb30eb44248c0e71730956d6cf79db101e68107a1d86217fd7345e226326d3dbd30406e83f503f9c17bf2ed456fec1
7
+ data.tar.gz: c725fb1fc3ddb65472a67496bf5cb0b9ac572bf60c737a021d28b06f179e02a41b94993459a3c2904ce0a5eea99dbb81d69b27ae86901cc55cd72e012b46ec58
data/.dockerignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .byebug_history
data/Dockerfile CHANGED
@@ -1,8 +1,17 @@
1
- FROM ruby:3.0.2-alpine3.14
1
+ FROM ruby:3.0.3-alpine AS builder
2
2
 
3
- RUN apk update && apk upgrade
4
- RUN apk add bash
5
- RUN apk add curl-dev ruby-dev build-base git curl ruby-json openssl groff mandoc man-pages
3
+ RUN apk --update add --no-cache \
4
+ curl-dev \
5
+ ruby-dev \
6
+ build-base \
7
+ git \
8
+ curl \
9
+ ruby-json \
10
+ openssl \
11
+ groff \
12
+ mandoc \
13
+ man-pages \
14
+ bash
6
15
 
7
16
  RUN mkdir -p /gem
8
17
  WORKDIR /gem
@@ -10,14 +19,28 @@ WORKDIR /gem
10
19
  ENV GEM_HOME="/usr/local/bundle"
11
20
  ENV PATH $GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH
12
21
 
13
- RUN gem install uffizzi-cli
14
- RUN gem install bundler -v 2.3.8
22
+ RUN gem install bundler -v 2.3.9
15
23
 
16
- COPY lib/uffizzi/version.rb /gem/lib/uffizzi/
17
- COPY uffizzi.gemspec /gem/
18
- COPY Gemfile* /gem/
24
+ COPY lib/uffizzi/version.rb ./lib/uffizzi/
25
+ COPY uffizzi.gemspec .
26
+ COPY Gemfile* .
19
27
  RUN bundle install --jobs 4
20
28
 
21
- COPY . /gem
29
+ COPY . .
22
30
 
23
- CMD ["uffizzi"]
31
+ RUN bundle exec rake install
32
+
33
+ # M-M-M-M-MULTISTAGE!!!
34
+ FROM ruby:3.0.3-alpine
35
+
36
+ RUN apk --update add --no-cache mandoc
37
+
38
+ WORKDIR /root/
39
+
40
+ COPY docker-entrypoint.sh .
41
+ RUN chmod +x docker-entrypoint.sh
42
+
43
+ COPY --from=builder /gem/pkg/uffizzi-cli* .
44
+ RUN gem install ./uffizzi-cli*
45
+
46
+ ENTRYPOINT ["/root/docker-entrypoint.sh"]
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- uffizzi-cli (0.2.2)
4
+ uffizzi-cli (0.3.4)
5
5
  thor
6
6
 
7
7
  GEM
@@ -16,6 +16,7 @@ GEM
16
16
  addressable (2.8.0)
17
17
  public_suffix (>= 2.0.2, < 5.0)
18
18
  ast (2.4.2)
19
+ bump (0.10.0)
19
20
  byebug (11.1.3)
20
21
  coderay (1.1.3)
21
22
  concurrent-ruby (1.1.9)
@@ -23,6 +24,8 @@ GEM
23
24
  rexml
24
25
  factory_bot (6.2.0)
25
26
  activesupport (>= 5.0.0)
27
+ faker (2.20.0)
28
+ i18n (>= 1.8.11, < 2)
26
29
  hashdiff (1.0.1)
27
30
  i18n (1.8.11)
28
31
  concurrent-ruby (~> 1.0)
@@ -95,9 +98,11 @@ PLATFORMS
95
98
  x86_64-linux-musl
96
99
 
97
100
  DEPENDENCIES
101
+ bump
98
102
  bundler (~> 2.2)
99
103
  byebug
100
104
  factory_bot
105
+ faker
101
106
  minitest
102
107
  minitest-power_assert
103
108
  mocha
data/Makefile ADDED
@@ -0,0 +1,32 @@
1
+ .PHONY: release release_patch release_minor release_major
2
+
3
+ NEXT_PATCH=$(shell docker-compose run --rm gem bash -c "bundle exec bump show-next patch")
4
+ NEXT_MINOR=$(shell docker-compose run --rm gem bash -c "bundle exec bump show-next minor")
5
+ NEXT_MAJOR=$(shell docker-compose run --rm gem bash -c "bundle exec bump show-next major")
6
+
7
+ release_patch: export VERSION=${NEXT_PATCH}
8
+ release_patch:
9
+ make release
10
+
11
+ release_minor: export VERSION=${NEXT_MINOR}
12
+ release_minor:
13
+ make release
14
+
15
+ release_major: export VERSION=${NEXT_MAJOR}
16
+ release_major:
17
+ make release
18
+
19
+ release:
20
+ git checkout develop
21
+ git pull origin --rebase develop
22
+ @echo 'Set a new version'
23
+ docker-compose run --rm gem bash -c "bundle exec bump set ${VERSION}"
24
+ @echo 'Update remote origin'
25
+ git push origin develop
26
+ git checkout main
27
+ git pull origin --rebase main
28
+ git merge --no-ff --no-edit develop
29
+ git push origin main
30
+ @echo 'Create a new tag'
31
+ git tag v${VERSION}
32
+ git push origin v${VERSION}
data/README.md CHANGED
@@ -29,10 +29,10 @@ To host Uffizzi yourself, you will also need the following external dependencies
29
29
 
30
30
  ## Installation
31
31
 
32
- Add this line to your application's Gemfile:
32
+ Add this line to your application's `Gemfile`:
33
33
 
34
34
  ```ruby
35
- gem 'uffizzi'
35
+ gem 'uffizzi-cli'
36
36
  ```
37
37
 
38
38
  And then execute:
@@ -41,7 +41,23 @@ And then execute:
41
41
 
42
42
  Or install it yourself as:
43
43
 
44
- $ gem install uffizzi
44
+ $ gem install uffizzi-cli
45
+
46
+ ### Docker image
47
+
48
+ We also provide an image on Docker Hub:
49
+
50
+ ```bash
51
+ docker run -it --rm uffizzi/cli project list
52
+ ```
53
+
54
+ If you specify the following environment variables, the Docker image's
55
+ entrypoint script can log you into Uffizzi before executing your command.
56
+
57
+ - `UFFIZZI_USER`
58
+ - `UFFIZZI_HOSTNAME`
59
+ - `UFFIZZI_PASSWORD`
60
+ - `UFFIZZI_PROJECT` (optional)
45
61
 
46
62
  ## Development
47
63
 
@@ -52,12 +68,23 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
52
68
  Run rubocop:
53
69
  `bundle exec rubocop -A`
54
70
 
71
+ ## Testing
72
+
73
+ Run tests:
74
+ `bundle exec rake test`
75
+
76
+ Run tests from a file:
77
+ `bundle exec rake test TEST=test/uffizzi/cli/preview_test.rb`
78
+
79
+ Run single test
80
+ `bundle exec rake test TEST=test/uffizzi/cli/preview_test.rb TESTOPTS="--name=test_name"`
81
+
55
82
  ## Commands
56
83
 
57
84
  ### login
58
85
 
59
86
  ```
60
- $ uffizzi login -u your@email.com --hostname localhost:8080
87
+ $ uffizzi login --user your@email.com --hostname localhost:8080
61
88
  ```
62
89
 
63
90
  Logging you into the app which you set in the hostname option.
@@ -167,7 +194,7 @@ git checkout -b feature/short_issue_description (e.g. feature/add_domain_setting
167
194
  ```
168
195
  git add .
169
196
  git commit -m 'short commit description' (e.g. git commit -m 'added domain settings')
170
- git push origin FEATURE_NAME
197
+ git push origin BRANCH_NAME
171
198
  ```
172
199
 
173
200
  4. You already can create PR with develop branch as a target. Once the feature is ready let us know in the channel - we will review
@@ -176,7 +203,7 @@ git push origin FEATURE_NAME
176
203
  ```
177
204
  git checkout qa
178
205
  git pull --rebase qa
179
- git merge --no-ff FEATURE_NAME
206
+ git merge --no-ff BRANCH_NAME
180
207
  git push origin qa
181
208
  ```
182
209
 
data/config/uffizzi.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ostruct'
4
+
4
5
  module Uffizzi
5
6
  def self.configuration
6
7
  @configuration ||= OpenStruct.new
@@ -12,5 +13,11 @@ module Uffizzi
12
13
 
13
14
  configure do |config|
14
15
  config.hostname = 'http://web:7000'
16
+ config.credential_types = {
17
+ dockerhub: 'UffizziCore::Credential::DockerHub',
18
+ azure: 'UffizziCore::Credential::Azure',
19
+ google: 'UffizziCore::Credential::Google',
20
+ amazon: 'UffizziCore::Credential::Amazon',
21
+ }
15
22
  end
16
23
  end
data/docker-compose.yml CHANGED
@@ -2,7 +2,9 @@ version: "3.9"
2
2
 
3
3
  services:
4
4
  gem:
5
- build: .
5
+ build:
6
+ context: .
7
+ target: builder
6
8
  volumes:
7
9
  - ./:/gem:cached
8
10
  - ~/.ssh:/root/.ssh
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+
3
+ set -e # Exit immediately if anything below exits with non-zero status.
4
+
5
+ if
6
+ [ $UFFIZZI_USER ] &&
7
+ [ $UFFIZZI_HOSTNAME ] &&
8
+ [ $UFFIZZI_PASSWORD ]
9
+ then
10
+ uffizzi login --username "${UFFIZZI_USER}" --hostname "${UFFIZZI_HOSTNAME}"
11
+ if [ $UFFIZZI_PROJECT ]
12
+ then
13
+ uffizzi config set project "${UFFIZZI_PROJECT}"
14
+ fi
15
+ else
16
+ echo "Specify environment variables to login before executing Uffizzi CLI."
17
+ echo "UFFIZZI_USER, UFFIZZI_HOSTNAME, UFFIZZI_PASSWORD, and optionally UFFIZZI_PROJECT"
18
+ fi
19
+
20
+ exec uffizzi "$@"
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'io/console'
4
3
  require 'uffizzi'
5
4
  require 'uffizzi/clients/api/api_client'
6
5
 
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uffizzi'
4
+
5
+ module Uffizzi
6
+ class CLI::Connect
7
+ include ApiClient
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 'gcr'
18
+ handle_google(credential_file_path)
19
+ else
20
+ Uffizzi.ui.say('Unsupported credential type.')
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def handle_docker_hub
27
+ username = Uffizzi.ui.ask('Username: ')
28
+ password = Uffizzi.ui.ask('Password: ', echo: false)
29
+
30
+ params = {
31
+ username: username,
32
+ password: password,
33
+ type: Uffizzi.configuration.credential_types[:dockerhub],
34
+ }
35
+
36
+ hostname = ConfigFile.read_option(:hostname)
37
+ response = create_credential(hostname, params)
38
+
39
+ if ResponseHelper.created?(response)
40
+ print_success_message('DockerHub')
41
+ else
42
+ ResponseHelper.handle_failed_response(response)
43
+ end
44
+ end
45
+
46
+ def handle_azure
47
+ registry_url = prepare_registry_url(Uffizzi.ui.ask('Registry Domain: '))
48
+ username = Uffizzi.ui.ask('Docker ID: ')
49
+ password = Uffizzi.ui.ask('Password/Access Token: ', echo: false)
50
+
51
+ params = {
52
+ username: username,
53
+ password: password,
54
+ registry_url: registry_url,
55
+ type: Uffizzi.configuration.credential_types[:azure],
56
+ }
57
+
58
+ hostname = ConfigFile.read_option(:hostname)
59
+ response = create_credential(hostname, params)
60
+
61
+ if ResponseHelper.created?(response)
62
+ print_success_message('ACR')
63
+ else
64
+ ResponseHelper.handle_failed_response(response)
65
+ end
66
+ end
67
+
68
+ def handle_amazon
69
+ registry_url = prepare_registry_url(Uffizzi.ui.ask('Registry Domain: '))
70
+ username = Uffizzi.ui.ask('Access key ID: ')
71
+ password = Uffizzi.ui.ask('Secret access key: ', echo: false)
72
+
73
+ params = {
74
+ username: username,
75
+ password: password,
76
+ registry_url: registry_url,
77
+ type: Uffizzi.configuration.credential_types[:amazon],
78
+ }
79
+
80
+ hostname = ConfigFile.read_option(:hostname)
81
+ response = create_credential(hostname, params)
82
+
83
+ if ResponseHelper.created?(response)
84
+ print_success_message('ECR')
85
+ else
86
+ ResponseHelper.handle_failed_response(response)
87
+ end
88
+ end
89
+
90
+ def handle_google(credential_file_path)
91
+ return Uffizzi.ui.say('Path to google service account key file wasn\'t specified.') if credential_file_path.nil?
92
+
93
+ begin
94
+ credential_content = File.read(credential_file_path)
95
+ rescue Errno::ENOENT => e
96
+ return Uffizzi.ui.say(e)
97
+ end
98
+
99
+ params = {
100
+ password: credential_content,
101
+ type: Uffizzi.configuration.credential_types[:google],
102
+ }
103
+
104
+ hostname = ConfigFile.read_option(:hostname)
105
+ response = create_credential(hostname, params)
106
+
107
+ if ResponseHelper.created?(response)
108
+ print_success_message('GCR')
109
+ else
110
+ ResponseHelper.handle_failed_response(response)
111
+ end
112
+ end
113
+
114
+ def prepare_registry_url(registry_url)
115
+ return registry_url if registry_url.match?(/^(?:http(s)?:\/\/)/)
116
+
117
+ "https://#{registry_url}"
118
+ end
119
+
120
+ def print_success_message(connection_name)
121
+ Uffizzi.ui.say("Successfully connected to #{connection_name}")
122
+ end
123
+ end
124
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'io/console'
4
3
  require 'uffizzi'
5
4
  require 'uffizzi/response_helper'
6
5
  require 'uffizzi/clients/api/api_client'
@@ -14,7 +13,8 @@ module Uffizzi
14
13
  end
15
14
 
16
15
  def run
17
- password = IO::console.getpass('Enter Password: ')
16
+ password = ENV['UFFIZZI_PASSWORD'] || IO::console.getpass('Enter Password: ')
17
+
18
18
  params = prepare_request_params(password)
19
19
  response = create_session(@options[:hostname], params)
20
20
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'io/console'
4
3
  require 'uffizzi'
5
4
  require 'uffizzi/auth_helper'
6
5
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uffizzi'
4
+ require 'uffizzi/auth_helper'
5
+ require 'uffizzi/response_helper'
6
+ require 'uffizzi/services/preview_service'
7
+
8
+ module Uffizzi
9
+ class CLI::Preview::Service < Thor
10
+ include ApiClient
11
+
12
+ desc 'list', 'list'
13
+ def list(deployment_name)
14
+ 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?
16
+
17
+ project_slug = ConfigFile.read_option(:project)
18
+ hostname = ConfigFile.read_option(:hostname)
19
+ deployment_id = PreviewService.read_deployment_id(deployment_name)
20
+ response = fetch_deployment_services(hostname, project_slug, deployment_id)
21
+
22
+ if ResponseHelper.ok?(response)
23
+ handle_succeed_response(response, deployment_name)
24
+ else
25
+ ResponseHelper.handle_failed_response(response)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def handle_succeed_response(response, deployment_name)
32
+ services = response[:body][:containers] || []
33
+ return Uffizzi.ui.say("There are no services associated with the preview #{deployment_name}") if services.empty?
34
+
35
+ services.each do |service|
36
+ Uffizzi.ui.say(service)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -3,6 +3,7 @@
3
3
  require 'uffizzi'
4
4
  require 'tty-spinner'
5
5
  require 'uffizzi/auth_helper'
6
+ require 'uffizzi/services/preview_service'
6
7
 
7
8
  module Uffizzi
8
9
  class CLI::Preview < Thor
@@ -16,37 +17,48 @@ module Uffizzi
16
17
  end
17
18
  end
18
19
 
20
+ desc 'service', 'service'
21
+ require_relative 'preview/service'
22
+ subcommand 'service', Uffizzi::CLI::Preview::Service
23
+
19
24
  desc 'list', 'list'
20
25
  def list
21
26
  return Cli::Common.show_manual(:list) if options[:help]
22
27
 
23
- run(options, 'list', nil, nil)
28
+ run(options, 'list')
24
29
  end
25
30
 
26
31
  desc 'create', 'create'
27
32
  def create(file_path = nil)
28
33
  return Cli::Common.show_manual(:create) if options[:help]
29
34
 
30
- run(options, 'create', file_path, nil)
35
+ run(options, 'create', file_path: file_path)
31
36
  end
32
37
 
33
38
  desc 'delete', 'delete'
34
- def delete(deployment)
39
+ def delete(deployment_name)
35
40
  return Cli::Common.show_manual(:delete) if options[:help]
36
41
 
37
- run(options, 'delete', nil, deployment)
42
+ run(options, 'delete', deployment_name: deployment_name)
38
43
  end
39
44
 
40
45
  desc 'describe', 'describe'
41
- def describe(deployment)
46
+ def describe(deployment_name)
42
47
  return Cli::Common.show_manual(:describe) if options[:help]
43
48
 
44
- run(options, 'describe', nil, deployment)
49
+ run(options, 'describe', deployment_name: deployment_name)
50
+ end
51
+
52
+ desc 'events', 'events'
53
+ def events(deployment_name)
54
+ return Cli::Common.show_manual(:events) if options[:help]
55
+
56
+ run(options, 'events', deployment_name: deployment_name)
45
57
  end
46
58
 
47
59
  private
48
60
 
49
- def run(options, command, file_path, deployment)
61
+ def run(options, command, file_path: nil, deployment_name: nil)
50
62
  return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
51
63
  return Uffizzi.ui.say('This command needs project to be set in config file') unless Uffizzi::AuthHelper.project_set?
52
64
 
@@ -58,15 +70,16 @@ module Uffizzi
58
70
  when 'create'
59
71
  handle_create_command(file_path, project_slug)
60
72
  when 'delete'
61
- handle_delete_command(deployment, project_slug)
73
+ handle_delete_command(deployment_name, project_slug)
62
74
  when 'describe'
63
- handle_describe_command(deployment, project_slug)
75
+ handle_describe_command(deployment_name, project_slug)
76
+ when 'events'
77
+ handle_events_command(deployment_name, project_slug)
64
78
  end
65
79
  end
66
80
 
67
81
  def handle_list_command(project_slug)
68
- hostname = ConfigFile.read_option(:hostname)
69
- response = fetch_deployments(hostname, project_slug)
82
+ response = fetch_deployments(ConfigFile.read_option(:hostname), project_slug)
70
83
 
71
84
  if ResponseHelper.ok?(response)
72
85
  handle_succeed_list_response(response)
@@ -76,33 +89,50 @@ module Uffizzi
76
89
  end
77
90
 
78
91
  def handle_create_command(file_path, project_slug)
79
- hostname = ConfigFile.read_option(:hostname)
80
92
  params = file_path.nil? ? {} : prepare_params(file_path)
81
- response = create_deployment(hostname, project_slug, params)
93
+ response = create_deployment(ConfigFile.read_option(:hostname), project_slug, params)
82
94
 
83
95
  if ResponseHelper.created?(response)
84
- handle_succeed_create_response(hostname, project_slug, response)
96
+ handle_succeed_create_response(project_slug, response)
97
+ else
98
+ ResponseHelper.handle_failed_response(response)
99
+ end
100
+ end
101
+
102
+ def handle_events_command(deployment_name, project_slug)
103
+ deployment_id = PreviewService.read_deployment_id(deployment_name)
104
+
105
+ return Uffizzi.ui.say("Preview should be specified in 'deployment-PREVIEW_ID' format") if deployment_id.nil?
106
+
107
+ response = fetch_events(ConfigFile.read_option(:hostname), project_slug, deployment_id)
108
+
109
+ if ResponseHelper.ok?(response)
110
+ handle_succeed_events_response(response)
85
111
  else
86
112
  ResponseHelper.handle_failed_response(response)
87
113
  end
88
114
  end
89
115
 
90
- def handle_succeed_create_response(hostname, project_slug, response)
116
+ def handle_succeed_events_response(response)
117
+ Uffizzi.ui.print_in_columns(response[:body][:events])
118
+ end
119
+
120
+ def handle_succeed_create_response(project_slug, response)
91
121
  deployment = response[:body][:deployment]
92
122
  deployment_id = deployment[:id]
93
123
  params = { id: deployment_id }
94
124
 
95
- response = deploy_containers(hostname, project_slug, deployment_id, params)
125
+ response = deploy_containers(ConfigFile.read_option(:hostname), project_slug, deployment_id, params)
96
126
 
97
127
  if ResponseHelper.no_content?(response)
98
128
  Uffizzi.ui.say("Preview created with name deployment-#{deployment_id}")
99
- print_deployment_progress(hostname, deployment, project_slug)
129
+ print_deployment_progress(deployment, project_slug)
100
130
  else
101
131
  ResponseHelper.handle_failed_response(response)
102
132
  end
103
133
  end
104
134
 
105
- def print_deployment_progress(hostname, deployment, project_slug)
135
+ def print_deployment_progress(deployment, project_slug)
106
136
  deployment_id = deployment[:id]
107
137
 
108
138
  @spinner = TTY::Spinner.new('[:spinner] Creating containers...', format: :dots)
@@ -111,7 +141,7 @@ module Uffizzi
111
141
  activity_items = []
112
142
 
113
143
  loop do
114
- response = get_activity_items(hostname, project_slug, deployment_id)
144
+ response = get_activity_items(ConfigFile.read_option(:hostname), project_slug, deployment_id)
115
145
  handle_activity_items_response(response)
116
146
  return unless @spinner.spinning?
117
147
 
@@ -133,7 +163,7 @@ module Uffizzi
133
163
  containers_spinners = create_containers_spinners(activity_items)
134
164
 
135
165
  loop do
136
- response = get_activity_items(hostname, project_slug, deployment_id)
166
+ response = get_activity_items(ConfigFile.read_option(:hostname), project_slug, deployment_id)
137
167
  handle_activity_items_response(response)
138
168
  return if @spinner.done?
139
169
 
@@ -176,13 +206,12 @@ module Uffizzi
176
206
  end
177
207
  end
178
208
 
179
- def handle_delete_command(deployment, project_slug)
180
- return Uffizzi.ui.say("Preview should be specified in 'deployment-PREVIEW_ID' format") unless deployment_name_valid?(deployment)
209
+ def handle_delete_command(deployment_name, project_slug)
210
+ deployment_id = PreviewService.read_deployment_id(deployment_name)
181
211
 
182
- hostname = ConfigFile.read_option(:hostname)
183
- deployment_id = deployment.split('-').last
212
+ return Uffizzi.ui.say("Preview should be specified in 'deployment-PREVIEW_ID' format") if deployment_id.nil?
184
213
 
185
- response = delete_deployment(hostname, project_slug, deployment_id)
214
+ response = delete_deployment(ConfigFile.read_option(:hostname), project_slug, deployment_id)
186
215
 
187
216
  if ResponseHelper.no_content?(response)
188
217
  handle_succeed_delete_response(deployment_id)
@@ -191,13 +220,12 @@ module Uffizzi
191
220
  end
192
221
  end
193
222
 
194
- def handle_describe_command(deployment, project_slug)
195
- return Uffizzi.ui.say("Preview should be specified in 'deployment-PREVIEW_ID' format") unless deployment_name_valid?(deployment)
223
+ def handle_describe_command(deployment_name, project_slug)
224
+ deployment_id = PreviewService.read_deployment_id(deployment_name)
196
225
 
197
- hostname = ConfigFile.read_option(:hostname)
198
- deployment_id = deployment.split('-').last
226
+ return Uffizzi.ui.say("Preview should be specified in 'deployment-PREVIEW_ID' format") if deployment_id.nil?
199
227
 
200
- response = describe_deployment(hostname, project_slug, deployment_id)
228
+ response = describe_deployment(ConfigFile.read_option(:hostname), project_slug, deployment_id)
201
229
 
202
230
  if ResponseHelper.ok?(response)
203
231
  handle_succeed_describe_response(response)
@@ -255,13 +283,5 @@ module Uffizzi
255
283
  dependencies: dependencies,
256
284
  }
257
285
  end
258
-
259
- def deployment_name_valid?(deployment)
260
- return false unless deployment.start_with?('deployment-')
261
- return false unless deployment.split('-').size == 2
262
-
263
- deployment_id = deployment.split('-').last
264
- deployment_id.to_i.to_s == deployment_id
265
- end
266
286
  end
267
287
  end
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'io/console'
4
3
  require 'uffizzi'
5
4
  require 'uffizzi/auth_helper'
6
5
  require 'uffizzi/response_helper'
7
6
  require 'uffizzi/services/compose_file_service'
8
7
  require 'uffizzi/services/env_variables_service'
9
- require 'thor'
10
8
 
11
9
  module Uffizzi
12
10
  class CLI::Project::Compose < Thor
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uffizzi'
4
+ require 'uffizzi/auth_helper'
5
+ require 'uffizzi/response_helper'
6
+ require 'uffizzi/shell'
7
+
8
+ module Uffizzi
9
+ class CLI::Project::Secret < Thor
10
+ include ApiClient
11
+
12
+ desc 'list', 'List Secrets'
13
+ def list
14
+ run('list')
15
+ end
16
+
17
+ desc 'create', 'Create secrets'
18
+ def create(id)
19
+ run('create', id)
20
+ end
21
+
22
+ desc 'delete', 'Delete a secret'
23
+ def delete(id)
24
+ run('delete', id)
25
+ end
26
+
27
+ private
28
+
29
+ def run(command, args = {})
30
+ return Uffizzi.ui.say('You are not logged in') unless AuthHelper.signed_in?
31
+
32
+ project_slug = ConfigFile.read_option(:project)
33
+ return Uffizzi.ui.say('Please use the --project option to specify the project name') if project_slug.nil?
34
+
35
+ case command
36
+ when 'list'
37
+ handle_list_command(project_slug)
38
+ when 'create'
39
+ handle_create_command(project_slug, args)
40
+ when 'delete'
41
+ handle_delete_command(project_slug, args)
42
+ else
43
+ error_message = "The subcommand #{command} does not exist, please run 'uffizzi project secret help' \
44
+ to get the list of available subcommands"
45
+ Uffizzi.ui.say(error_message)
46
+ end
47
+ end
48
+
49
+ def handle_list_command(project_slug)
50
+ hostname = ConfigFile.read_option(:hostname)
51
+ response = fetch_secrets(hostname, project_slug)
52
+ secrets = response[:body][:secrets].map { |secret| [secret[:name]] }
53
+ return Uffizzi.ui.say('There are no secrets for the project') if secrets.empty?
54
+
55
+ table_header = 'NAME'
56
+ table_data = [[table_header], *secrets]
57
+ return Uffizzi.ui.print_table(table_data) if ResponseHelper.ok?(response)
58
+
59
+ ResponseHelper.handle_failed_response(response)
60
+ end
61
+
62
+ def handle_create_command(project_slug, id)
63
+ hostname = ConfigFile.read_option(:hostname)
64
+ secret_value = $stdin.read
65
+ return Uffizzi.ui.say('Please provide the secret value') if secret_value.nil?
66
+
67
+ params = { secrets: [{ name: id, value: secret_value }] }
68
+ response = bulk_create_secrets(hostname, project_slug, params)
69
+ return Uffizzi.ui.say('The secret was successfully created') if ResponseHelper.created?(response)
70
+
71
+ ResponseHelper.handle_failed_response(response)
72
+ end
73
+
74
+ def handle_delete_command(project_slug, id)
75
+ hostname = ConfigFile.read_option(:hostname)
76
+ response = delete_secret(hostname, project_slug, id)
77
+
78
+ if ResponseHelper.no_content?(response)
79
+ Uffizzi.ui.say('The secret was successfully deleted')
80
+ else
81
+ ResponseHelper.handle_failed_response(response)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'io/console'
4
3
  require 'uffizzi'
5
4
  require 'uffizzi/auth_helper'
6
5
  require 'uffizzi/response_helper'
7
- require 'thor'
8
6
 
9
7
  module Uffizzi
10
8
  class CLI::Project < Thor
@@ -15,6 +13,10 @@ module Uffizzi
15
13
  require_relative 'project/compose'
16
14
  subcommand 'compose', Uffizzi::CLI::Project::Compose
17
15
 
16
+ desc 'secret', 'Secrets Actions'
17
+ require_relative 'project/secret'
18
+ subcommand 'secret', Uffizzi::CLI::Project::Secret
19
+
18
20
  desc 'list', 'list'
19
21
  def list
20
22
  run('list')
data/lib/uffizzi/cli.rb CHANGED
@@ -30,6 +30,12 @@ module Uffizzi
30
30
  Logout.new.run
31
31
  end
32
32
 
33
+ desc 'projects', 'projects'
34
+ def projects
35
+ require_relative 'cli/projects'
36
+ Projects.new.run
37
+ end
38
+
33
39
  desc 'project', 'project'
34
40
  require_relative 'cli/project'
35
41
  subcommand 'project', CLI::Project
@@ -42,5 +48,11 @@ module Uffizzi
42
48
  method_option :project, required: false
43
49
  require_relative 'cli/preview'
44
50
  subcommand 'preview', CLI::Preview
51
+
52
+ desc 'connect CREDENTIAL_TYPE', 'Connect credentials into Uffizzi'
53
+ def connect(credential_type, credential_file_path = nil)
54
+ require_relative 'cli/connect'
55
+ Connect.new.run(credential_type, credential_file_path)
56
+ end
45
57
  end
46
58
  end
@@ -5,6 +5,7 @@ require_relative 'http_client'
5
5
 
6
6
  module ApiClient
7
7
  include ApiRoutes
8
+
8
9
  def create_session(hostname, params = {})
9
10
  uri = session_uri(hostname)
10
11
  response = Uffizzi::HttpClient.make_post_request(uri, params, false)
@@ -26,6 +27,20 @@ module ApiClient
26
27
  build_response(response)
27
28
  end
28
29
 
30
+ def create_credential(hostname, params)
31
+ uri = credentials_uri(hostname)
32
+ response = Uffizzi::HttpClient.make_post_request(uri, params)
33
+
34
+ build_response(response)
35
+ end
36
+
37
+ def fetch_deployment_services(hostname, project_slug, deployment_id)
38
+ uri = preview_services_uri(hostname, project_slug, deployment_id)
39
+ response = Uffizzi::HttpClient.make_get_request(uri)
40
+
41
+ build_response(response)
42
+ end
43
+
29
44
  def set_compose_file(hostname, params, project_slug)
30
45
  uri = compose_file_uri(hostname, project_slug)
31
46
  response = Uffizzi::HttpClient.make_post_request(uri, params)
@@ -35,7 +50,28 @@ module ApiClient
35
50
 
36
51
  def unset_compose_file(hostname, project_slug)
37
52
  uri = compose_file_uri(hostname, project_slug)
38
- response = Uffizzi::HttpClient.make_delete_request(uri, true)
53
+ response = Uffizzi::HttpClient.make_delete_request(uri)
54
+
55
+ build_response(response)
56
+ end
57
+
58
+ def fetch_secrets(hostname, project_slug)
59
+ uri = secrets_uri(hostname, project_slug)
60
+ response = Uffizzi::HttpClient.make_get_request(uri)
61
+
62
+ build_response(response)
63
+ end
64
+
65
+ def bulk_create_secrets(hostname, project_slug, params)
66
+ uri = "#{secrets_uri(hostname, project_slug)}/bulk_create"
67
+ response = Uffizzi::HttpClient.make_post_request(uri, params)
68
+
69
+ build_response(response)
70
+ end
71
+
72
+ def delete_secret(hostname, project_slug, id)
73
+ uri = secret_uri(hostname, project_slug, id)
74
+ response = Uffizzi::HttpClient.make_delete_request(uri)
39
75
 
40
76
  build_response(response)
41
77
  end
@@ -70,7 +106,7 @@ module ApiClient
70
106
 
71
107
  def delete_deployment(hostname, project_slug, deployment_id)
72
108
  uri = deployment_uri(hostname, project_slug, deployment_id)
73
- response = Uffizzi::HttpClient.make_delete_request(uri, true)
109
+ response = Uffizzi::HttpClient.make_delete_request(uri)
74
110
 
75
111
  build_response(response)
76
112
  end
@@ -82,6 +118,13 @@ module ApiClient
82
118
  build_response(response)
83
119
  end
84
120
 
121
+ def fetch_events(hostname, project_slug, deployment_id)
122
+ uri = events_uri(hostname, project_slug, deployment_id)
123
+ response = Uffizzi::HttpClient.make_get_request(uri)
124
+
125
+ build_response(response)
126
+ end
127
+
85
128
  def get_activity_items(hostname, project_slug, deployment_id)
86
129
  uri = activity_items_uri(hostname, project_slug, deployment_id)
87
130
  response = Uffizzi::HttpClient.make_get_request(uri)
@@ -1,16 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'cgi'
4
+
3
5
  module ApiRoutes
4
- def session_uri(hostname)
5
- "#{hostname}/api/cli/v1/session"
6
+ def compose_file_uri(hostname, project_slug)
7
+ "#{hostname}/api/cli/v1/projects/#{project_slug}/compose_file"
6
8
  end
7
9
 
8
10
  def projects_uri(hostname)
9
11
  "#{hostname}/api/cli/v1/projects"
10
12
  end
11
13
 
12
- def compose_file_uri(hostname, project_slug)
13
- "#{hostname}/api/cli/v1/projects/#{project_slug}/compose_file"
14
+ def secret_uri(hostname, project_slug, id)
15
+ path_id = CGI.escape(id)
16
+ "#{hostname}/api/cli/v1/projects/#{project_slug}/secrets/#{path_id}"
17
+ end
18
+
19
+ def secrets_uri(hostname, project_slug)
20
+ "#{hostname}/api/cli/v1/projects/#{project_slug}/secrets"
21
+ end
22
+
23
+ def session_uri(hostname)
24
+ "#{hostname}/api/cli/v1/session"
14
25
  end
15
26
 
16
27
  def validate_compose_file_uri(hostname, project_slug)
@@ -32,4 +43,16 @@ module ApiRoutes
32
43
  def deploy_containers_uri(hostname, project_slug, deployment_id)
33
44
  "#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/deploy_containers"
34
45
  end
46
+
47
+ def events_uri(hostname, project_slug, deployment_id)
48
+ "#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/events"
49
+ end
50
+
51
+ def credentials_uri(hostname)
52
+ "#{hostname}/api/cli/v1/account/credentials"
53
+ end
54
+
55
+ def preview_services_uri(hostname, project_slug, deployment_id)
56
+ "#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/containers"
57
+ end
35
58
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PreviewService
4
+ class << self
5
+ def read_deployment_id(deployment_name)
6
+ return nil unless deployment_name.start_with?('deployment-')
7
+ return nil unless deployment_name.split('-').size == 2
8
+
9
+ deployment_id = deployment_name.split('-').last
10
+ return nil if deployment_id.to_i.to_s != deployment_id
11
+
12
+ deployment_id
13
+ end
14
+ end
15
+ end
data/lib/uffizzi/shell.rb CHANGED
@@ -9,8 +9,16 @@ module Uffizzi
9
9
  @shell = Thor::Shell::Basic.new
10
10
  end
11
11
 
12
- def say(msg)
13
- @shell.say(msg)
12
+ def say(message)
13
+ @shell.say(message)
14
+ end
15
+
16
+ def print_in_columns(messages)
17
+ @shell.print_in_columns(messages)
18
+ end
19
+
20
+ def print_table(table_data)
21
+ @shell.print_table(table_data)
14
22
  end
15
23
 
16
24
  def last_message
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Uffizzi
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.4'
5
5
  end
data/lib/uffizzi.rb CHANGED
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'io/console'
4
+
3
5
  require 'uffizzi/shell'
4
6
  require 'uffizzi/version'
5
7
  require 'uffizzi/clients/api/api_client'
6
8
  require 'uffizzi/clients/api/api_routes'
7
9
  require 'uffizzi/config_file'
10
+ require_relative '../config/uffizzi'
8
11
 
9
12
  module Uffizzi
10
13
  class Error < StandardError; end
@@ -0,0 +1,30 @@
1
+ .\" generated with Ronn-NG/v0.9.1
2
+ .\" http://github.com/apjanke/ronn-ng/tree/0.9.1
3
+ .TH "UFFIZZI\-EVENTS" "" "March 2022" ""
4
+ .SH "NAME"
5
+ \fBuffizzi preview events \- show the deployment event logs for a preview\fR
6
+ .P
7
+ .SH SYNOPSIS
8
+ uffizzi preview events [PREVIEW_ID] [UFFIZZI_WIDE_FLAG \|\.\|\.\|\.]
9
+ .P
10
+ .SH DESCRIPTION
11
+ Shows the deployment event logs for a given preview\.
12
+
13
+ This command can fail for the following reasons:
14
+ \- There is no preview with the given PREVIEW_ID
15
+
16
+ For more information on event logs, see:
17
+ https://docs\.uffizzi\.com/cli
18
+
19
+ .SH POSITIONAL ARGUMENTS
20
+ [PREVIEW_ID]
21
+ The ID of the preview that you want to see events for\.
22
+ .P
23
+ .SH UFFIZZI WIDE FLAGS
24
+ These flags are available to all commands: \-\-project\. Run $ uffizzi help for details\.
25
+ .P
26
+ .SH EXAMPLES
27
+ The following command shows deployment events for the preview with ID deployment\-67:
28
+ .P
29
+ $ uffizzi preview events deployment\-67
30
+
@@ -0,0 +1,29 @@
1
+ NAME
2
+ uffizzi preview events - show the deployment event logs for a
3
+ preview
4
+
5
+ SYNOPSIS
6
+ uffizzi preview events [PREVIEW_ID] [UFFIZZI_WIDE_FLAG ...]
7
+
8
+ DESCRIPTION
9
+ Shows the deployment event logs for a given preview.
10
+
11
+ This command can fail for the following reasons:
12
+ - There is no preview with the given PREVIEW_ID
13
+
14
+ For more information on event logs, see:
15
+ https://docs.uffizzi.com/cli
16
+
17
+ POSITIONAL ARGUMENTS
18
+ [PREVIEW_ID]
19
+ The ID of the preview that you want to see events for.
20
+
21
+ UFFIZZI WIDE FLAGS
22
+ These flags are available to all commands: --project. Run $ uffizzi
23
+ help for details.
24
+
25
+ EXAMPLES
26
+ The following command shows deployment events for the preview with
27
+ ID deployment-67:
28
+
29
+ $ uffizzi preview events deployment-67
data/uffizzi.gemspec CHANGED
@@ -27,9 +27,11 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
+ spec.add_development_dependency 'bump'
30
31
  spec.add_development_dependency 'bundler', '~> 2.2'
31
32
  spec.add_development_dependency 'byebug'
32
33
  spec.add_development_dependency 'factory_bot'
34
+ spec.add_development_dependency 'faker'
33
35
  spec.add_development_dependency 'minitest'
34
36
  spec.add_development_dependency 'minitest-power_assert'
35
37
  spec.add_development_dependency 'mocha'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uffizzi-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Thurman
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-03-22 00:00:00.000000000 Z
12
+ date: 2022-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bump
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: bundler
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -53,6 +67,20 @@ dependencies:
53
67
  - - ">="
54
68
  - !ruby/object:Gem::Version
55
69
  version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: faker
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
56
84
  - !ruby/object:Gem::Dependency
57
85
  name: minitest
58
86
  requirement: !ruby/object:Gem::Requirement
@@ -257,6 +285,7 @@ executables:
257
285
  extensions: []
258
286
  extra_rdoc_files: []
259
287
  files:
288
+ - ".dockerignore"
260
289
  - ".rubocop.yml"
261
290
  - CHANGELOG.md
262
291
  - CONTRIBUTING.md
@@ -264,24 +293,28 @@ files:
264
293
  - Gemfile
265
294
  - Gemfile.lock
266
295
  - LICENSE
296
+ - Makefile
267
297
  - README.md
268
298
  - Rakefile
269
299
  - bin/console
270
300
  - bin/setup
271
- - config/config.rb
272
301
  - config/uffizzi.rb
273
302
  - docker-compose.yml
303
+ - docker-entrypoint.sh
274
304
  - exe/uffizzi
275
305
  - lib/uffizzi.rb
276
306
  - lib/uffizzi/auth_helper.rb
277
307
  - lib/uffizzi/cli.rb
278
308
  - lib/uffizzi/cli/common.rb
279
309
  - lib/uffizzi/cli/config.rb
310
+ - lib/uffizzi/cli/connect.rb
280
311
  - lib/uffizzi/cli/login.rb
281
312
  - lib/uffizzi/cli/logout.rb
282
313
  - lib/uffizzi/cli/preview.rb
314
+ - lib/uffizzi/cli/preview/service.rb
283
315
  - lib/uffizzi/cli/project.rb
284
316
  - lib/uffizzi/cli/project/compose.rb
317
+ - lib/uffizzi/cli/project/secret.rb
285
318
  - lib/uffizzi/clients/api/api_client.rb
286
319
  - lib/uffizzi/clients/api/api_routes.rb
287
320
  - lib/uffizzi/clients/api/http_client.rb
@@ -289,6 +322,7 @@ files:
289
322
  - lib/uffizzi/response_helper.rb
290
323
  - lib/uffizzi/services/compose_file_service.rb
291
324
  - lib/uffizzi/services/env_variables_service.rb
325
+ - lib/uffizzi/services/preview_service.rb
292
326
  - lib/uffizzi/shell.rb
293
327
  - lib/uffizzi/version.rb
294
328
  - man/uffizzi-create
@@ -297,6 +331,8 @@ files:
297
331
  - man/uffizzi-delete.ronn
298
332
  - man/uffizzi-describe
299
333
  - man/uffizzi-describe.ronn
334
+ - man/uffizzi-events
335
+ - man/uffizzi-events.ronn
300
336
  - man/uffizzi-list
301
337
  - man/uffizzi-list.ronn
302
338
  - man/uffizzi-logout
data/config/config.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ostruct'
4
-
5
- module Uffizzi
6
- def self.configuration
7
- @configuration ||= OpenStruct.new
8
- end
9
-
10
- def self.configure
11
- yield(configuration)
12
- end
13
-
14
- configure do |config|
15
- config.hostname = 'http://web:7000'
16
- end
17
- end