sem 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.rubocop.yml +103 -0
- data/Gemfile +6 -0
- data/README.md +27 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/sem +5 -0
- data/guides.md +168 -0
- data/ids.md +74 -0
- data/lib/sem.rb +53 -0
- data/lib/sem/api.rb +14 -0
- data/lib/sem/api/base.rb +17 -0
- data/lib/sem/api/env_vars.rb +20 -0
- data/lib/sem/api/files.rb +19 -0
- data/lib/sem/api/orgs.rb +54 -0
- data/lib/sem/api/projects.rb +33 -0
- data/lib/sem/api/shared_configs.rb +75 -0
- data/lib/sem/api/teams.rb +54 -0
- data/lib/sem/api/traits.rb +9 -0
- data/lib/sem/api/traits/associated_with_org.rb +13 -0
- data/lib/sem/api/traits/associated_with_shared_config.rb +29 -0
- data/lib/sem/api/traits/associated_with_team.rb +29 -0
- data/lib/sem/api/users.rb +26 -0
- data/lib/sem/api/users_with_permissions.rb +53 -0
- data/lib/sem/cli.rb +20 -0
- data/lib/sem/cli/orgs.rb +45 -0
- data/lib/sem/cli/projects.rb +17 -0
- data/lib/sem/cli/shared_configs.rb +97 -0
- data/lib/sem/cli/teams.rb +126 -0
- data/lib/sem/errors.rb +8 -0
- data/lib/sem/version.rb +3 -0
- data/lib/sem/views.rb +7 -0
- data/lib/sem/views/base.rb +7 -0
- data/lib/sem/views/env_vars.rb +13 -0
- data/lib/sem/views/files.rb +13 -0
- data/lib/sem/views/orgs.rb +22 -0
- data/lib/sem/views/projects.rb +22 -0
- data/lib/sem/views/shared_configs.rb +24 -0
- data/lib/sem/views/teams.rb +24 -0
- data/lib/sem/views/users.rb +13 -0
- data/lib/sem/views/users_with_permissions.rb +13 -0
- data/sem.gemspec +33 -0
- 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
|
data/lib/sem/cli/orgs.rb
ADDED
@@ -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
data/lib/sem/version.rb
ADDED
data/lib/sem/views.rb
ADDED
@@ -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,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
|