sem 0.1.1

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +103 -0
  5. data/Gemfile +6 -0
  6. data/README.md +27 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/exe/sem +5 -0
  11. data/guides.md +168 -0
  12. data/ids.md +74 -0
  13. data/lib/sem.rb +53 -0
  14. data/lib/sem/api.rb +14 -0
  15. data/lib/sem/api/base.rb +17 -0
  16. data/lib/sem/api/env_vars.rb +20 -0
  17. data/lib/sem/api/files.rb +19 -0
  18. data/lib/sem/api/orgs.rb +54 -0
  19. data/lib/sem/api/projects.rb +33 -0
  20. data/lib/sem/api/shared_configs.rb +75 -0
  21. data/lib/sem/api/teams.rb +54 -0
  22. data/lib/sem/api/traits.rb +9 -0
  23. data/lib/sem/api/traits/associated_with_org.rb +13 -0
  24. data/lib/sem/api/traits/associated_with_shared_config.rb +29 -0
  25. data/lib/sem/api/traits/associated_with_team.rb +29 -0
  26. data/lib/sem/api/users.rb +26 -0
  27. data/lib/sem/api/users_with_permissions.rb +53 -0
  28. data/lib/sem/cli.rb +20 -0
  29. data/lib/sem/cli/orgs.rb +45 -0
  30. data/lib/sem/cli/projects.rb +17 -0
  31. data/lib/sem/cli/shared_configs.rb +97 -0
  32. data/lib/sem/cli/teams.rb +126 -0
  33. data/lib/sem/errors.rb +8 -0
  34. data/lib/sem/version.rb +3 -0
  35. data/lib/sem/views.rb +7 -0
  36. data/lib/sem/views/base.rb +7 -0
  37. data/lib/sem/views/env_vars.rb +13 -0
  38. data/lib/sem/views/files.rb +13 -0
  39. data/lib/sem/views/orgs.rb +22 -0
  40. data/lib/sem/views/projects.rb +22 -0
  41. data/lib/sem/views/shared_configs.rb +24 -0
  42. data/lib/sem/views/teams.rb +24 -0
  43. data/lib/sem/views/users.rb +13 -0
  44. data/lib/sem/views/users_with_permissions.rb +13 -0
  45. data/sem.gemspec +33 -0
  46. metadata +201 -0
@@ -0,0 +1,53 @@
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
+ groups.sort_by { |permission, _| LEVELS[permission] }.to_h.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
+ users.map { |user| [user.username, transform_user(user, team)] }.to_h
45
+ end
46
+
47
+ def transform_user(user, team)
48
+ Users.to_hash(user).merge(:permission => team.permission)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/sem/cli.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Sem
2
+ class CLI < Dracula
3
+ program_name "sem"
4
+
5
+ require_relative "cli/orgs"
6
+ require_relative "cli/projects"
7
+ require_relative "cli/teams"
8
+ require_relative "cli/shared_configs"
9
+
10
+ desc "login", "log in to semaphore from the command line"
11
+ def login
12
+ puts "NOT IMPLEMENTED"
13
+ end
14
+
15
+ register "orgs", "manage organizations", Sem::CLI::Orgs
16
+ register "teams", "manage teams and team membership", Sem::CLI::Teams
17
+ register "shared-configs", "manage shared configurations", Sem::CLI::SharedConfigs
18
+ register "projects", "manage projects", Sem::CLI::Projects
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ class Sem::CLI::Orgs < Dracula
2
+
3
+ desc "list", "list organizations"
4
+ def list
5
+ orgs = Sem::API::Orgs.list
6
+
7
+ Sem::Views::Orgs.list(orgs)
8
+ end
9
+
10
+ desc "info", "shows detailed information about an organization"
11
+ def info(org_name)
12
+ org = Sem::API::Orgs.info(org_name)
13
+
14
+ Sem::Views::Orgs.info(org)
15
+ end
16
+
17
+ desc "members", "list members of an organization"
18
+ option :with_2fa,
19
+ :default => false,
20
+ :type => :boolean,
21
+ :desc => "list members that have two factor authentication enabled"
22
+ option :admins,
23
+ :default => false,
24
+ :type => :boolean,
25
+ :desc => "list only admins in the organization"
26
+ option :owners,
27
+ :default => false,
28
+ :type => :boolean,
29
+ :desc => "list only owners in the organization"
30
+ def members(org_name)
31
+ raise "Not Implemented" if options[:with_2fa]
32
+
33
+ users =
34
+ if options[:owners]
35
+ Sem::API::UsersWithPermissions.list_owners_for_org(org_name)
36
+ elsif options[:admins]
37
+ Sem::API::UsersWithPermissions.list_admins_for_org(org_name)
38
+ else
39
+ Sem::API::UsersWithPermissions.list_for_org(org_name)
40
+ end
41
+
42
+ Sem::Views::UsersWithPermissions.list(users)
43
+ end
44
+
45
+ end
@@ -0,0 +1,17 @@
1
+ class Sem::CLI::Projects < Dracula
2
+
3
+ desc "list", "list projects"
4
+ def list
5
+ projects = Sem::API::Projects.list
6
+
7
+ Sem::Views::Projects.list(projects)
8
+ end
9
+
10
+ desc "info", "shows detailed information about a project"
11
+ def info(project_path)
12
+ project = Sem::API::Projects.info(project_path)
13
+
14
+ Sem::Views::Projects.info(project)
15
+ end
16
+
17
+ end
@@ -0,0 +1,97 @@
1
+ class Sem::CLI::SharedConfigs < Dracula
2
+
3
+ desc "list", "list shared cofigurations"
4
+ def list
5
+ shared_configs = Sem::API::SharedConfigs.list
6
+
7
+ Sem::Views::SharedConfigs.list(shared_configs)
8
+ end
9
+
10
+ desc "info", "show information about a shared configuration"
11
+ def info(path)
12
+ shared_config = Sem::API::SharedConfigs.info(path)
13
+
14
+ Sem::Views::SharedConfigs.info(shared_config)
15
+ end
16
+
17
+ desc "create", "create a new shared configuration"
18
+ def create(path)
19
+ org_name, shared_config_name = path.split("/")
20
+
21
+ shared_config = Sem::API::SharedConfigs.create(org_name, :name => shared_config_name)
22
+
23
+ Sem::Views::SharedConfigs.info(shared_config)
24
+ end
25
+
26
+ desc "rename", "rename a shared configuration"
27
+ def rename(old_path, new_path)
28
+ _, name = new_path.split("/")
29
+
30
+ shared_config = Sem::API::SharedConfigs.update(old_path, :name => name)
31
+
32
+ Sem::Views::SharedConfigs.info(shared_config)
33
+ end
34
+
35
+ desc "delete", "removes a shared configuration from your organization"
36
+ def delete(path)
37
+ Sem::API::SharedConfigs.delete(path)
38
+
39
+ puts "Deleted shared configuration #{path}"
40
+ end
41
+
42
+ class Files < Dracula
43
+ desc "list", "list files in the shared configuration"
44
+ def list(shared_config_path)
45
+ files = Sem::API::SharedConfigs.list_files(shared_config_path)
46
+
47
+ Sem::Views::Files.list(files)
48
+ end
49
+
50
+ desc "add", "add a file to the shared configuration"
51
+ option :file, :aliases => "f", :desc => "File to upload", :required => true
52
+ def add(shared_config_path, file_name)
53
+ content = File.read(options[:file])
54
+
55
+ Sem::API::Files.add_to_shared_config(shared_config_path, :path => file_name, :content => content)
56
+
57
+ puts "Added #{file_name} to #{shared_config_path}"
58
+ end
59
+
60
+ desc "remove", "remove a file from the shared configuration"
61
+ def remove(shared_config_path, file_name)
62
+ Sem::API::Files.remove_from_shared_config(shared_config_path, file_name)
63
+
64
+ puts "Removed #{file_name} from #{shared_config_path}"
65
+ end
66
+ end
67
+
68
+ class EnvVars < Dracula
69
+ desc "list", "list environment variables in the shared configuration"
70
+ def list(shared_config_path)
71
+ env_vars = Sem::API::SharedConfigs.list_env_vars(shared_config_path)
72
+
73
+ Sem::Views::EnvVars.list(env_vars)
74
+ end
75
+
76
+ desc "add", "add an environment variable to the shared configuration"
77
+ option :name, :aliases => "-n", :desc => "Name of the variable", :required => true
78
+ option :content, :aliases => "-c", :desc => "Content of the variable", :required => true
79
+ def add(shared_config_path)
80
+ Sem::API::EnvVars.add_to_shared_config(shared_config_path,
81
+ :name => options[:name],
82
+ :content => options[:content])
83
+
84
+ puts "Added #{options[:name]} to #{shared_config_path}"
85
+ end
86
+
87
+ desc "remove", "remove an environment variable from the shared configuration"
88
+ def remove(shared_config_path, env_var_name)
89
+ Sem::API::EnvVars.remove_from_shared_config(shared_config_path, env_var_name)
90
+
91
+ puts "Removed #{env_var_name} from #{shared_config_path}"
92
+ end
93
+ end
94
+
95
+ register "files", "manage files", Files
96
+ register "env-vars", "manage environment variables", EnvVars
97
+ end
@@ -0,0 +1,126 @@
1
+ class Sem::CLI::Teams < Dracula
2
+
3
+ desc "list", "list teams"
4
+ def list
5
+ teams = Sem::API::Teams.list
6
+
7
+ Sem::Views::Teams.list(teams)
8
+ end
9
+
10
+ desc "info", "show information about a team"
11
+ def info(name)
12
+ team = Sem::API::Teams.info(name)
13
+
14
+ Sem::Views::Teams.info(team)
15
+ end
16
+
17
+ desc "create", "create a new team"
18
+ option :permission, :default => "read",
19
+ :aliases => "-p",
20
+ :desc => "Permission level of the team in the organization"
21
+ def create(name)
22
+ org_name, team_name = name.split("/")
23
+
24
+ team = Sem::API::Teams.create(org_name,
25
+ :name => team_name,
26
+ :permission => options[:permission])
27
+
28
+ Sem::Views::Teams.info(team)
29
+ end
30
+
31
+ desc "rename", "change the name of the team"
32
+ def rename(old_name, new_name)
33
+ _, name = new_name.split("/")
34
+
35
+ team = Sem::API::Teams.update(old_name, :name => name)
36
+
37
+ Sem::Views::Teams.info(team)
38
+ end
39
+
40
+ desc "set-permission", "set the permission level of the team"
41
+ def set_permission(team_name, permission)
42
+ team = Sem::API::Teams.update(team_name, :permission => permission)
43
+
44
+ Sem::Views::Teams.info(team)
45
+ end
46
+
47
+ desc "delete", "removes a team from your organization"
48
+ def delete(name)
49
+ Sem::API::Teams.delete(name)
50
+
51
+ puts "Deleted team #{name}"
52
+ end
53
+
54
+ class Members < Dracula
55
+ desc "list", "lists members of the team"
56
+ def list(team_name)
57
+ members = Sem::API::Users.list_for_team(team_name)
58
+
59
+ Sem::Views::Users.list(members)
60
+ end
61
+
62
+ desc "add", "add a user to the team"
63
+ def add(team_name, username)
64
+ Sem::API::Users.add_to_team(team_name, username)
65
+
66
+ puts "User #{username} added to the team."
67
+ end
68
+
69
+ desc "remove", "removes a user from the team"
70
+ def remove(team_name, username)
71
+ Sem::API::Users.remove_from_team(team_name, username)
72
+
73
+ puts "User #{username} removed from the team."
74
+ end
75
+ end
76
+
77
+ class Projects < Dracula
78
+ desc "list", "lists projects in a team"
79
+ def list(team_name)
80
+ projects = Sem::API::Projects.list_for_team(team_name)
81
+
82
+ Sem::Views::Projects.list(projects)
83
+ end
84
+
85
+ desc "add", "add a project to a team"
86
+ def add(team_name, project_name)
87
+ Sem::API::Projects.add_to_team(team_name, project_name)
88
+
89
+ puts "Project #{project_name} added to the team."
90
+ end
91
+
92
+ desc "remove", "removes a project from the team"
93
+ def remove(team_name, project_name)
94
+ Sem::API::Projects.remove_from_team(team_name, project_name)
95
+
96
+ puts "Project #{project_name} removed from the team."
97
+ end
98
+ end
99
+
100
+ class SharedConfigs < Dracula
101
+ desc "list", "list shared configurations in a team"
102
+ def list(team_name)
103
+ configs = Sem::API::SharedConfigs.list_for_team(team_name)
104
+
105
+ Sem::Views::SharedConfigs.list(configs)
106
+ end
107
+
108
+ desc "add", "add a shared configuration to a team"
109
+ def add(team_name, shared_config_name)
110
+ Sem::API::SharedConfigs.add_to_team(team_name, shared_config_name)
111
+
112
+ puts "Shared Configuration #{shared_config_name} added to the team."
113
+ end
114
+
115
+ desc "remove", "removes a project from the team"
116
+ def remove(team_name, shared_config_name)
117
+ Sem::API::SharedConfigs.remove_from_team(team_name, shared_config_name)
118
+
119
+ puts "Shared Configuration #{shared_config_name} removed from the team."
120
+ end
121
+ end
122
+
123
+ register "members", "manage team members", Members
124
+ register "projects", "manage team members", Projects
125
+ register "shared-configs", "manage shared configurations", SharedConfigs
126
+ end
data/lib/sem/errors.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Sem::Errors
2
+ Base = Class.new(StandardError)
3
+
4
+ module Auth
5
+ NoCredentials = Class.new(Sem::Errors::Base)
6
+ InvalidCredentials = Class.new(Sem::Errors::Base)
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Sem
2
+ VERSION = "0.1.1".freeze
3
+ end
data/lib/sem/views.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Sem
2
+ class Views
3
+ require_relative "views/base"
4
+
5
+ Dir["lib/sem/views/**/*.rb"].each { |f| require_relative f.gsub(%r{^lib/sem/}, "") }
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Sem::Views::Base
2
+
3
+ def self.print_table(table)
4
+ Dracula::UI.print_table(table)
5
+ end
6
+
7
+ end
@@ -0,0 +1,13 @@
1
+ class Sem::Views::EnvVars < Sem::Views::Base
2
+
3
+ def self.list(env_vars)
4
+ header = ["ID", "NAME", "ENCRYPTED?", "CONTENT"]
5
+
6
+ body = env_vars.map do |env_var|
7
+ [env_var[:id], env_var[:name], env_var[:encrypted?], env_var[:content]]
8
+ end
9
+
10
+ print_table([header, *body])
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ class Sem::Views::Files < Sem::Views::Base
2
+
3
+ def self.list(files)
4
+ header = ["ID", "NAME", "ENCRYPTED?"]
5
+
6
+ body = files.map do |file|
7
+ [file[:id], file[:name], file[:encrypted?]]
8
+ end
9
+
10
+ print_table([header, *body])
11
+ end
12
+
13
+ end
@@ -0,0 +1,22 @@
1
+ class Sem::Views::Orgs < Sem::Views::Base
2
+
3
+ def self.list(orgs)
4
+ header = ["ID", "NAME"]
5
+
6
+ body = orgs.map do |org|
7
+ [org[:id], org[:username]]
8
+ end
9
+
10
+ print_table [header, *body]
11
+ end
12
+
13
+ def self.info(org)
14
+ print_table [
15
+ ["ID", org[:id]],
16
+ ["Name", org[:username]],
17
+ ["Created", org[:created_at]],
18
+ ["Updated", org[:updated_at]]
19
+ ]
20
+ end
21
+
22
+ end