sem 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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