uffizzi-cli 0.2.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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