sem 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ module Sem
2
+ class Pagination
3
+ class << self
4
+ def pages(pages_per_call, &block)
5
+ instances = []
6
+ index = 1
7
+
8
+ loop do
9
+ pages = range_map(index, pages_per_call, &block)
10
+
11
+ instances += pages.select { |page| !(page.nil? || page.empty?) }
12
+ index += pages_per_call
13
+
14
+ break instances if pages.any? { |page| page.nil? || page.empty? }
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def range_map(start_index, pages_per_call)
21
+ end_index = start_index + pages_per_call - 1
22
+
23
+ (start_index..end_index).to_a.pmap do |page_index|
24
+ yield(page_index)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/sem/srn.rb ADDED
@@ -0,0 +1,42 @@
1
+ class Sem::SRN
2
+ # Semaphore Resource Name
3
+
4
+ class << self
5
+ def parse_org(semaphore_resource_name)
6
+ parse_srn(semaphore_resource_name, "org_name")
7
+ end
8
+
9
+ def parse_team(semaphore_resource_name)
10
+ parse_srn(semaphore_resource_name, "org_name/team_name")
11
+ end
12
+
13
+ def parse_project(semaphore_resource_name)
14
+ parse_srn(semaphore_resource_name, "org_name/project_name")
15
+ end
16
+
17
+ def parse_shared_config(semaphore_resource_name)
18
+ parse_srn(semaphore_resource_name, "org_name/shared_config_name")
19
+ end
20
+
21
+ def parse_user(semaphore_resource_name)
22
+ parse_srn(semaphore_resource_name, "user_name")
23
+ end
24
+
25
+ private
26
+
27
+ def parse_srn(semaphore_resource_name, format)
28
+ srn_tokens = semaphore_resource_name.to_s.split("/")
29
+ format_tokens = format.split("/")
30
+
31
+ if srn_tokens.count != format_tokens.count
32
+ resource = format_tokens.last.split("_").tap(&:pop).join(" ").capitalize
33
+
34
+ message = "#{resource} \"#{semaphore_resource_name}\" not found."
35
+
36
+ raise Sem::Errors::InvalidSRN, message
37
+ end
38
+
39
+ srn_tokens
40
+ end
41
+ end
42
+ end
data/lib/sem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sem
2
- VERSION = "0.1.4".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -1,7 +1,12 @@
1
1
  class Sem::Views::Base
2
+ class << self
3
+ def print_table(table)
4
+ Dracula::UI.print_table(table)
5
+ end
2
6
 
3
- def self.print_table(table)
4
- Dracula::UI.print_table(table)
7
+ def org_names_not_matching(resource1, resource2, srn1, srn2)
8
+ "[ERROR] Organization names not matching.\n\n" \
9
+ "#{resource1.capitalize} \"#{srn1}\" and #{resource2} \"#{srn2}\" are not in the same organization."
10
+ end
5
11
  end
6
-
7
12
  end
@@ -1,6 +1,15 @@
1
1
  class Sem::Views::Orgs < Sem::Views::Base
2
2
 
3
3
  def self.list(orgs)
4
+ if orgs.empty?
5
+ puts "You don't belong to any organization."
6
+ puts ""
7
+ puts "Create your first organization: https://semaphoreci.com/organizations/new."
8
+ puts ""
9
+
10
+ return
11
+ end
12
+
4
13
  header = ["ID", "NAME"]
5
14
 
6
15
  body = orgs.map do |org|
@@ -1,22 +1,39 @@
1
1
  class Sem::Views::Projects < Sem::Views::Base
2
+ class << self
3
+ def list(projects)
4
+ if projects.empty?
5
+ puts "You don't have any project configured on Semaphore."
6
+ puts ""
7
+ puts "Add your first project: https://semaphoreci.com/new"
8
+ puts ""
2
9
 
3
- def self.list(projects)
4
- header = ["ID", "NAME"]
10
+ return
11
+ end
5
12
 
6
- body = projects.map do |project|
7
- [project[:id], project[:name]]
13
+ header = ["ID", "NAME"]
14
+
15
+ body = projects.map do |project|
16
+ [project[:id], name(project)]
17
+ end
18
+
19
+ print_table([header, *body])
8
20
  end
9
21
 
10
- print_table([header, *body])
11
- end
22
+ def info(project)
23
+ print_table [
24
+ ["ID", project[:id]],
25
+ ["Name", name(project)],
26
+ ["Created", project[:created_at]],
27
+ ["Updated", project[:updated_at]]
28
+ ]
29
+ end
12
30
 
13
- def self.info(org)
14
- print_table [
15
- ["ID", org[:id]],
16
- ["Name", org[:name]],
17
- ["Created", org[:created_at]],
18
- ["Updated", org[:updated_at]]
19
- ]
20
- end
31
+ private
32
+
33
+ def name(project)
34
+ return unless project[:org] && project[:name]
21
35
 
36
+ "#{project[:org]}/#{project[:name]}"
37
+ end
38
+ end
22
39
  end
@@ -1,6 +1,17 @@
1
1
  class Sem::Views::SharedConfigs < Sem::Views::Base
2
2
 
3
3
  def self.list(configs)
4
+ if configs.empty?
5
+ puts "You don't have any shared configurations on Semaphore."
6
+ puts ""
7
+ puts "Create your first shared configuration:"
8
+ puts ""
9
+ puts " sem shared-config:create ORG_NAME/SHARED_CONFIG"
10
+ puts ""
11
+
12
+ return
13
+ end
14
+
4
15
  header = ["ID", "NAME", "CONFIG FILES", "ENV VARS"]
5
16
 
6
17
  body = configs.map do |config|
@@ -1,24 +1,76 @@
1
1
  class Sem::Views::Teams < Sem::Views::Base
2
+ class << self
3
+ def list(teams)
4
+ if teams.empty?
5
+ puts "You don't have any teams on Semaphore."
6
+ puts ""
7
+ puts "Create your first team:"
8
+ puts ""
9
+ puts " sem teams:create ORG_NAME/TEAM"
10
+ puts ""
2
11
 
3
- def self.list(teams)
4
- header = ["ID", "NAME", "PERMISSION", "MEMBERS"]
12
+ return
13
+ end
5
14
 
6
- body = teams.map do |team|
7
- [team[:id], team[:name], team[:permission], "#{team[:members]} members"]
15
+ header = ["ID", "NAME", "PERMISSION", "MEMBERS"]
16
+
17
+ body = teams.map do |team|
18
+ [team[:id], "#{team[:org]}/#{team[:name]}", permission(team), "#{team[:members]} members"]
19
+ end
20
+
21
+ print_table [header, *body]
8
22
  end
9
23
 
10
- print_table [header, *body]
11
- end
24
+ def info(team)
25
+ print_table [
26
+ ["ID", team[:id]],
27
+ ["Name", name(team)],
28
+ ["Permission", permission(team)],
29
+ ["Members", members(team)],
30
+ ["Created", team[:created_at]],
31
+ ["Updated", team[:updated_at]]
32
+ ]
33
+ end
12
34
 
13
- def self.info(team)
14
- print_table [
15
- ["ID", team[:id]],
16
- ["Name", team[:name]],
17
- ["Permission", team[:permission]],
18
- ["Members", "#{team[:members]} members"],
19
- ["Created", team[:created_at]],
20
- ["Updated", team[:updated_at]]
21
- ]
22
- end
35
+ def list_members(team, members)
36
+ if members.empty?
37
+ puts "You don't have any members in the team."
38
+ puts ""
39
+ puts "Add your first member:"
40
+ puts ""
41
+ puts " sem teams:members:add #{team} USERNAME"
42
+ puts ""
43
+
44
+ return
45
+ end
46
+
47
+ header = ["NAME"]
48
+
49
+ body = members.map do |user|
50
+ [user[:id]]
51
+ end
52
+
53
+ print_table [header, *body]
54
+ end
23
55
 
56
+ private
57
+
58
+ def name(team)
59
+ return unless team[:org] && team[:name]
60
+
61
+ "#{team[:org]}/#{team[:name]}"
62
+ end
63
+
64
+ def members(team)
65
+ return unless team[:members]
66
+
67
+ "#{team[:members]} members"
68
+ end
69
+
70
+ def permission(team)
71
+ return "write" if team[:permission] == "edit"
72
+
73
+ team[:permission]
74
+ end
75
+ end
24
76
  end
@@ -1,13 +1,11 @@
1
1
  class Sem::Views::Users < Sem::Views::Base
2
+ class << self
3
+ def list(users)
4
+ header = ["NAME"]
2
5
 
3
- def self.list(users)
4
- header = ["NAME"]
6
+ body = users.map { |user| [user[:id]] }
5
7
 
6
- body = users.map do |user|
7
- [user[:id]]
8
+ print_table [header, *body]
8
9
  end
9
-
10
- print_table [header, *body]
11
10
  end
12
-
13
11
  end
data/lib/sem.rb CHANGED
@@ -2,21 +2,45 @@ require "sem/version"
2
2
  require "dracula"
3
3
  require "semaphore_client"
4
4
  require "fileutils"
5
+ require "pmap"
5
6
 
6
7
  module Sem
7
8
  require "sem/errors"
8
- require "sem/credentials"
9
+ require "sem/configuration"
10
+ require "sem/srn"
11
+ require "sem/pagination"
9
12
  require "sem/cli"
10
13
  require "sem/api"
11
14
  require "sem/views"
15
+ LOG_LEVEL_TRACE = :trace
16
+ LOG_LEVEL_ERROR = :error
12
17
 
13
18
  class << self
19
+ attr_writer :log_level
20
+
21
+ def log_level
22
+ @log_level || LOG_LEVEL_ERROR
23
+ end
14
24
 
15
25
  # Returns exit status as a number.
16
26
  def start(args)
27
+ if args.include?("--trace")
28
+ @log_level = LOG_LEVEL_TRACE
29
+
30
+ args.delete("--trace")
31
+ end
32
+
17
33
  Sem::CLI.start(args)
18
34
 
19
35
  0
36
+ rescue Sem::Errors::ResourceException => e
37
+ puts e.message
38
+
39
+ 1
40
+ rescue Sem::Errors::InvalidSRN => e
41
+ on_invalid_srn(e)
42
+
43
+ 1
20
44
  rescue Sem::Errors::Auth::NoCredentials
21
45
  on_no_credentials
22
46
 
@@ -33,6 +57,12 @@ module Sem
33
57
 
34
58
  private
35
59
 
60
+ def on_invalid_srn(exception)
61
+ puts "[ERROR] Invalid parameter formatting."
62
+ puts ""
63
+ puts exception.message
64
+ end
65
+
36
66
  def on_no_credentials
37
67
  puts "[ERROR] You are not logged in."
38
68
  puts ""
@@ -48,7 +78,10 @@ module Sem
48
78
  def on_unhandled_error(exception)
49
79
  puts "[PANIC] Unhandled error."
50
80
  puts ""
51
- puts "Well, this is emberassing. An unknown error was detected."
81
+ puts "Well, this is embarrassing. An unknown error was detected."
82
+ puts ""
83
+ puts "Exception:"
84
+ puts exception.message
52
85
  puts ""
53
86
  puts "Backtrace: "
54
87
  puts exception.backtrace
data/sem.gemspec CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_dependency "semaphore_client", "2.0.9"
25
- spec.add_dependency "dracula", "~> 0.1.1"
24
+ spec.add_dependency "semaphore_client", "2.1.3"
25
+ spec.add_dependency "dracula", "~> 0.3.0"
26
+ spec.add_dependency "pmap", "~> 1.1.1"
26
27
 
27
28
  spec.add_development_dependency "bundler", "~> 1.14"
28
29
  spec.add_development_dependency "rake", "~> 10.0"
@@ -30,5 +31,5 @@ Gem::Specification.new do |spec|
30
31
  spec.add_development_dependency "rubocop", "~> 0.47.1"
31
32
  spec.add_development_dependency "rubocop-rspec", "1.5.0"
32
33
  spec.add_development_dependency "simplecov", "~> 0.13"
33
- spec.add_development_dependency "byebug"
34
+ spec.add_development_dependency "byebug", "~> 9.0.0"
34
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Šarčević
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-18 00:00:00.000000000 Z
11
+ date: 2017-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semaphore_client
@@ -16,28 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.9
19
+ version: 2.1.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.9
26
+ version: 2.1.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dracula
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.1
33
+ version: 0.3.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.1
40
+ version: 0.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pmap
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -126,16 +140,16 @@ dependencies:
126
140
  name: byebug
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
- - - ">="
143
+ - - "~>"
130
144
  - !ruby/object:Gem::Version
131
- version: '0'
145
+ version: 9.0.0
132
146
  type: :development
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
- - - ">="
150
+ - - "~>"
137
151
  - !ruby/object:Gem::Version
138
- version: '0'
152
+ version: 9.0.0
139
153
  description: Semaphore CLI
140
154
  email:
141
155
  - igor@renderedtext.com
@@ -166,17 +180,19 @@ files:
166
180
  - lib/sem/api/teams.rb
167
181
  - lib/sem/api/traits.rb
168
182
  - lib/sem/api/traits/associated_with_org.rb
183
+ - lib/sem/api/traits/associated_with_project.rb
169
184
  - lib/sem/api/traits/associated_with_shared_config.rb
170
185
  - lib/sem/api/traits/associated_with_team.rb
171
186
  - lib/sem/api/users.rb
172
- - lib/sem/api/users_with_permissions.rb
173
187
  - lib/sem/cli.rb
174
188
  - lib/sem/cli/orgs.rb
175
189
  - lib/sem/cli/projects.rb
176
190
  - lib/sem/cli/shared_configs.rb
177
191
  - lib/sem/cli/teams.rb
178
- - lib/sem/credentials.rb
192
+ - lib/sem/configuration.rb
179
193
  - lib/sem/errors.rb
194
+ - lib/sem/pagination.rb
195
+ - lib/sem/srn.rb
180
196
  - lib/sem/version.rb
181
197
  - lib/sem/views.rb
182
198
  - lib/sem/views/base.rb
@@ -187,7 +203,6 @@ files:
187
203
  - lib/sem/views/shared_configs.rb
188
204
  - lib/sem/views/teams.rb
189
205
  - lib/sem/views/users.rb
190
- - lib/sem/views/users_with_permissions.rb
191
206
  - sem.gemspec
192
207
  homepage: https://github.com/renderedtext/cli
193
208
  licenses:
@@ -1,57 +0,0 @@
1
- module Sem
2
- module API
3
- class UsersWithPermissions < Base
4
- class << self
5
- LEVELS = { "owner" => 3, "admin" => 2, "write" => 1, "read" => 0 }.freeze
6
-
7
- def list_owners_for_org(org_name)
8
- Sem::API::Orgs.list_owners(org_name).map { |user| user.merge(:permission => "owner") }
9
- end
10
-
11
- def list_admins_for_org(org_name)
12
- Sem::API::Orgs.list_admins(org_name).map { |user| user.merge(:permission => "admin") }
13
- end
14
-
15
- def list_for_org(org_name)
16
- all_teams = client.teams.list_for_org(org_name)
17
-
18
- team_groups = teams_by_permission(all_teams)
19
-
20
- user_groups = users_for_team_groups(team_groups)
21
-
22
- user_groups.reduce({}) { |acc, teams| acc.merge(teams) }.values
23
- end
24
-
25
- private
26
-
27
- def teams_by_permission(all_teams)
28
- groups = all_teams.group_by(&:permission)
29
-
30
- to_hash(groups.sort_by { |permission, _| LEVELS[permission] }).values
31
- end
32
-
33
- def users_for_team_groups(groups)
34
- groups.map { |teams| users_for_teams(teams) }.flatten
35
- end
36
-
37
- def users_for_teams(teams)
38
- teams.map { |team| users_for_team(team) }.flatten.uniq
39
- end
40
-
41
- def users_for_team(team)
42
- users = client.users.list_for_team(team.id)
43
-
44
- to_hash(users.map { |user| [user.username, transform_user(user, team)] })
45
- end
46
-
47
- def transform_user(user, team)
48
- Users.to_hash(user).merge(:permission => team.permission)
49
- end
50
-
51
- def to_hash(array)
52
- Hash[array]
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,19 +0,0 @@
1
- module Sem
2
- class Credentials
3
- PATH = File.expand_path("~/.sem/credentials").freeze
4
-
5
- def self.write(auth_token)
6
- dirname = File.dirname(PATH)
7
- FileUtils.mkdir_p(dirname)
8
-
9
- File.write(PATH, auth_token)
10
- File.chmod(0o0600, PATH)
11
- end
12
-
13
- def self.read
14
- raise Sem::Errors::Auth::NoCredentials unless File.file?(PATH)
15
-
16
- File.read(PATH).strip
17
- end
18
- end
19
- end
@@ -1,13 +0,0 @@
1
- class Sem::Views::UsersWithPermissions < Sem::Views::Base
2
-
3
- def self.list(users)
4
- header = ["NAME", "PERMISSION"]
5
-
6
- body = users.map do |user|
7
- [user[:id], user[:permission]]
8
- end
9
-
10
- print_table [header, *body]
11
- end
12
-
13
- end