sem 0.1.4 → 0.2.0

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
  SHA1:
3
- metadata.gz: 69ad26460c2a5f0370942054823818fd4628feb0
4
- data.tar.gz: 3d66bfd1e6a4a0fc87ee9e34ac3a27795754774d
3
+ metadata.gz: ccd122f3ce04fc09324bb135463966fd91fe5d90
4
+ data.tar.gz: aff41dee6b2352c2844beb298c8a0ed5268ff5d0
5
5
  SHA512:
6
- metadata.gz: 26889f21ff8805815526af5f70db424d007cf23ffec5b6978b18559a56427d4890d5baa95685545d1d110350b1407786a7a36d92f7306951529ecd13d11c011f
7
- data.tar.gz: 687430ea92a6f952405e5a3a8983d301243bb58bef6fa8c58b2aa9135b20f7ee57bf36d8f8abd92f0536ba7d9928da00e6a91f8d25ecf3fa0f5551aca33cef8d
6
+ metadata.gz: fa93e1e6a31b3f5faf0ea12a32e1178acf2c3fa041105d403b95659b1321d75819b1862f3524fbcd64015f506a6736bf10ab50b82dab69097b85d030f2010448
7
+ data.tar.gz: a59bc4d8e6248700231099d8f36bac604bd7f0bfc6a15817addb1774b2b7b6082e58b7b2c784cb200a58d83785da1dffebc7279d90f77b086a679dc83ddc5d07
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Semaphore CLI
2
2
 
3
3
  [![Build Status](https://semaphoreci.com/api/v1/renderedtext/cli/branches/master/badge.svg)](https://semaphoreci.com/renderedtext/cli)
4
+ [![Gem Version](https://badge.fury.io/rb/sem.svg)](https://badge.fury.io/rb/sem)
4
5
 
5
6
  ![Semaphore logo](https://d1dkupr86d302v.cloudfront.net/assets/application_bootstrap/layout/semaphore-logo-a6d954e176b6975b511f314a0cc808dc94a8030210077e3a6e904fbe69dc5354.svg)
6
7
 
@@ -10,6 +11,22 @@ The Semaphore CLI is used to manage Semaphore projects from the command line.
10
11
 
11
12
  For more info about Semaphore see <https://www.semaphoreci.com>
12
13
 
14
+ ## Semaphore Resource Name (SRN)
15
+
16
+ SRN is a way of identifying Semaphore resources. This CLI uses SRNs as arguments
17
+ for all actions.
18
+
19
+ Formats for individual resources are the following:
20
+
21
+ - Organization: `organization_name`
22
+ - Team: `organization_name/team_name`
23
+ - Project: `organization_name/project_name`
24
+ - Shared Configuration: `organization_name/shared_configuration_name`
25
+
26
+ ## Using custom API URL
27
+
28
+ Create a file at `~/.sem/api_url` containing only the custom url.
29
+
13
30
  ## Issues
14
31
 
15
32
  For problems directly related to the CLI, [add an issue on GitHub](https://github.com/renderedtext/cli/issues/new).
data/lib/sem/api/base.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  module Sem
2
2
  module API
3
3
  class Base
4
- def self.client
5
- @client ||= begin
6
- auth_token = Sem::Credentials.read
7
-
8
- SemaphoreClient.new(auth_token)
4
+ class << self
5
+ def client
6
+ @client ||= SemaphoreClient.new(
7
+ Sem::Configuration.auth_token,
8
+ :api_url => Sem::Configuration.api_url,
9
+ :verbose => (Sem.log_level == Sem::LOG_LEVEL_TRACE)
10
+ )
9
11
  end
10
12
  end
11
13
  end
@@ -3,17 +3,19 @@ module Sem
3
3
  class EnvVars < Base
4
4
  extend Traits::AssociatedWithSharedConfig
5
5
 
6
- def self.api
7
- client.env_vars
8
- end
6
+ class << self
7
+ def api
8
+ client.env_vars
9
+ end
9
10
 
10
- def self.to_hash(env_var)
11
- {
12
- :id => env_var.id,
13
- :name => env_var.name,
14
- :encrypted? => env_var.encrypted,
15
- :content => env_var.content
16
- }
11
+ def to_hash(env_var)
12
+ {
13
+ :id => env_var.id,
14
+ :name => env_var.name,
15
+ :encrypted? => env_var.encrypted,
16
+ :content => env_var.content
17
+ }
18
+ end
17
19
  end
18
20
  end
19
21
  end
data/lib/sem/api/files.rb CHANGED
@@ -3,16 +3,18 @@ module Sem
3
3
  class Files < Base
4
4
  extend Traits::AssociatedWithSharedConfig
5
5
 
6
- def self.api
7
- client.config_files
8
- end
6
+ class << self
7
+ def api
8
+ client.config_files
9
+ end
9
10
 
10
- def self.to_hash(files)
11
- {
12
- :id => files.id,
13
- :name => files.path,
14
- :encrypted? => files.encrypted
15
- }
11
+ def to_hash(file)
12
+ {
13
+ :id => file.id,
14
+ :name => file.path,
15
+ :encrypted? => file.encrypted
16
+ }
17
+ end
16
18
  end
17
19
  end
18
20
  end
data/lib/sem/api/orgs.rb CHANGED
@@ -1,53 +1,41 @@
1
1
  module Sem
2
2
  module API
3
3
  class Orgs < Base
4
- def self.list
5
- orgs = api.list
4
+ class << self
5
+ def list
6
+ orgs = api.list
6
7
 
7
- orgs.map { |org| to_hash(org) }
8
- end
9
-
10
- def self.info(name)
11
- org = api.get(name)
12
-
13
- to_hash(org)
14
- end
15
-
16
- def self.list_teams(org_name)
17
- Sem::API::Teams.list_for_org(org_name)
18
- end
8
+ orgs.map { |org| to_hash(org) }
9
+ end
19
10
 
20
- def self.list_users(org_name)
21
- Sem::API::Users.list_for_org(org_name)
22
- end
23
-
24
- def self.list_admins(org_name)
25
- admin_teams = list_teams(org_name).select { |team| team[:permission] == "admin" }
26
-
27
- admins = admin_teams.map { |team| client.users.list_for_team(team[:id]) }.flatten
11
+ def info(name)
12
+ org = api.get(name)
28
13
 
29
- admins.map { |admin| Sem::API::Users.to_hash(admin) }
30
- end
14
+ raise Sem::Errors::ResourceNotFound.new("Organization", [name]) if org.nil?
31
15
 
32
- def self.list_owners(org_name)
33
- owners_team = list_teams(org_name).find { |team| team[:name] == "Owners" }
16
+ to_hash(org)
17
+ end
34
18
 
35
- owners = client.users.list_for_team(owners_team[:id])
19
+ def list_teams(name)
20
+ Sem::API::Teams.list_for_org(name)
21
+ end
36
22
 
37
- owners.map { |owner| Sem::API::Users.to_hash(owner) }
38
- end
23
+ def list_users(name)
24
+ Sem::API::Users.list_for_org(name)
25
+ end
39
26
 
40
- def self.api
41
- client.orgs
42
- end
27
+ def api
28
+ client.orgs
29
+ end
43
30
 
44
- def self.to_hash(org)
45
- {
46
- :id => org.id,
47
- :username => org.username,
48
- :created_at => org.created_at,
49
- :updated_at => org.updated_at
50
- }
31
+ def to_hash(org)
32
+ {
33
+ :id => org.id,
34
+ :username => org.username,
35
+ :created_at => org.created_at,
36
+ :updated_at => org.updated_at
37
+ }
38
+ end
51
39
  end
52
40
  end
53
41
  end
@@ -4,29 +4,38 @@ module Sem
4
4
  extend Traits::AssociatedWithOrg
5
5
  extend Traits::AssociatedWithTeam
6
6
 
7
- def self.list
8
- org_names = Orgs.list.map { |org| org[:username] }
7
+ class << self
8
+ def name_to_id(org_name, project_name)
9
+ info(org_name, project_name)[:id]
10
+ end
9
11
 
10
- org_names.map { |name| list_for_org(name) }.flatten
11
- end
12
+ def list
13
+ org_names = Orgs.list.map { |org| org[:username] }
12
14
 
13
- def self.info(path)
14
- org_name, project_name = path.split("/")
15
+ org_names.pmap { |name| list_for_org(name) }.flatten
16
+ end
15
17
 
16
- list_for_org(org_name).find { |project| project[:name] == project_name }
17
- end
18
+ def info(org_name, project_name)
19
+ project = api.list_for_org(org_name, :name => project_name).first
18
20
 
19
- def self.api
20
- client.projects
21
- end
21
+ raise Sem::Errors::ResourceNotFound.new("Project", [org_name, project_name]) if project.nil?
22
+
23
+ to_hash(project, org_name)
24
+ end
25
+
26
+ def api
27
+ client.projects
28
+ end
22
29
 
23
- def self.to_hash(project)
24
- {
25
- :id => project.id,
26
- :name => project.name,
27
- :created_at => project.created_at,
28
- :updated_at => project.updated_at
29
- }
30
+ def to_hash(project, org)
31
+ {
32
+ :id => project.id,
33
+ :name => project.name,
34
+ :org => org,
35
+ :created_at => project.created_at,
36
+ :updated_at => project.updated_at
37
+ }
38
+ end
30
39
  end
31
40
  end
32
41
  end
@@ -3,71 +3,99 @@ module Sem
3
3
  class SharedConfigs < Base
4
4
  extend Traits::AssociatedWithTeam
5
5
  extend Traits::AssociatedWithOrg
6
+ extend Traits::AssociatedWithProject
6
7
 
7
- def self.list
8
- org_names = Orgs.list.map { |org| org[:username] }
8
+ class << self
9
+ def name_to_id(org_name, shared_config_name)
10
+ info(org_name, shared_config_name)[:id]
11
+ end
9
12
 
10
- org_names.map { |name| list_for_org(name) }.flatten
11
- end
13
+ def list
14
+ org_names = Orgs.list.map { |org| org[:username] }
12
15
 
13
- def self.info(path)
14
- org_name, config_name = path.split("/")
16
+ org_names.pmap { |name| list_for_org(name) }.flatten
17
+ end
15
18
 
16
- list_for_org(org_name).find { |config| config[:name] == config_name }
17
- end
19
+ def info(org_name, shared_config_name)
20
+ selected_shared_config = list_for_org(org_name).find do |shared_config|
21
+ shared_config[:name] == shared_config_name
22
+ end
18
23
 
19
- def self.create(org_name, args)
20
- config = api.create_for_org(org_name, args)
24
+ if selected_shared_config.nil?
25
+ raise Sem::Errors::ResourceNotFound.new("Shared Configuration", [org_name, shared_config_name])
26
+ end
21
27
 
22
- to_hash(config)
23
- end
28
+ selected_shared_config
29
+ end
24
30
 
25
- def self.update(path, args)
26
- shared_config = info(path)
31
+ def create(org_name, args)
32
+ shared_config = api.create_for_org(org_name, args)
27
33
 
28
- shared_config = api.update(shared_config[:id], args)
34
+ if shared_config.nil?
35
+ raise Sem::Errors::ResourceNotCreated.new("Shared Configuration", [org_name, args[:name]])
36
+ end
29
37
 
30
- to_hash(shared_config)
31
- end
38
+ to_hash(shared_config, org_name)
39
+ end
32
40
 
33
- def self.delete(path)
34
- id = info(path)[:id]
41
+ def update(org_name, shared_config_name, args)
42
+ shared_config = info(org_name, shared_config_name)
35
43
 
36
- api.delete(id)
37
- end
44
+ shared_config = api.update(shared_config[:id], args)
38
45
 
39
- def self.list_env_vars(path)
40
- Sem::API::EnvVars.list_for_shared_config(path)
41
- end
46
+ if shared_config.nil?
47
+ raise Sem::Errors::ResourceNotUpdated.new("Shared Configuration", [org_name, shared_config_name])
48
+ end
42
49
 
43
- def self.list_files(path)
44
- Sem::API::Files.list_for_shared_config(path)
45
- end
50
+ to_hash(shared_config, org_name)
51
+ end
46
52
 
47
- def self.api
48
- client.shared_configs
49
- end
53
+ def delete(org_name, shared_config_name)
54
+ shared_config = info(org_name, shared_config_name)
50
55
 
51
- def self.to_hash(config)
52
- {
53
- :id => config.id,
54
- :name => config.name,
55
- :config_files => config_files_count(config.id),
56
- :env_vars => env_vars_count(config.id),
57
- :created_at => config.created_at,
58
- :updated_at => config.updated_at
59
- }
60
- end
56
+ api.delete!(shared_config[:id])
57
+ rescue SemaphoreClient::Exceptions::RequestFailed
58
+ raise Sem::Errors::ResourceNotDeleted.new("Shared Configuration", [org_name, shared_config_name])
59
+ end
60
+
61
+ def list_env_vars(org_name, shared_config_name)
62
+ Sem::API::EnvVars.list_for_shared_config(org_name, shared_config_name)
63
+ end
64
+
65
+ def list_files(org_name, shared_config_name)
66
+ Sem::API::Files.list_for_shared_config(org_name, shared_config_name)
67
+ end
68
+
69
+ def api
70
+ client.shared_configs
71
+ end
72
+
73
+ def to_hash(shared_config, org)
74
+ network_actions = [:config_files_count, :env_vars_count]
75
+
76
+ config_files, env_vars = network_actions.pmap do |action|
77
+ send(action, shared_config.id)
78
+ end
79
+
80
+ {
81
+ :id => shared_config.id,
82
+ :name => shared_config.name,
83
+ :org => org,
84
+ :config_files => config_files,
85
+ :env_vars => env_vars,
86
+ :created_at => shared_config.created_at,
87
+ :updated_at => shared_config.updated_at
88
+ }
89
+ end
61
90
 
62
- class << self
63
91
  private
64
92
 
65
- def config_files_count(config_id)
66
- client.config_files.list_for_shared_config(config_id).to_a.size
93
+ def config_files_count(shared_config_id)
94
+ client.config_files.list_for_shared_config(shared_config_id).to_a.size
67
95
  end
68
96
 
69
- def env_vars_count(config_id)
70
- client.env_vars.list_for_shared_config(config_id).to_a.size
97
+ def env_vars_count(shared_config_id)
98
+ client.env_vars.list_for_shared_config(shared_config_id).to_a.size
71
99
  end
72
100
  end
73
101
  end
data/lib/sem/api/teams.rb CHANGED
@@ -3,51 +3,66 @@ module Sem
3
3
  class Teams < Base
4
4
  extend Traits::AssociatedWithOrg
5
5
 
6
- def self.list
7
- org_names = Sem::API::Orgs.list.map { |org| org[:username] }
6
+ class << self
7
+ def name_to_id(org_name, team_name)
8
+ info(org_name, team_name)[:id]
9
+ end
8
10
 
9
- org_names.map { |name| list_for_org(name) }.flatten
10
- end
11
+ def list
12
+ org_names = Sem::API::Orgs.list.map { |org| org[:username] }
11
13
 
12
- def self.info(path)
13
- org_name, team_name = path.split("/")
14
+ org_names.pmap { |name| list_for_org(name) }.flatten
15
+ end
14
16
 
15
- list_for_org(org_name).find { |team| team[:name] == team_name }
16
- end
17
+ def info(org_name, team_name)
18
+ selected_team = list_for_org(org_name).find { |team| team[:name] == team_name }
17
19
 
18
- def self.create(org_name, args)
19
- team = api.create_for_org(org_name, args)
20
+ raise Sem::Errors::ResourceNotFound.new("Team", [org_name, team_name]) if selected_team.nil?
20
21
 
21
- to_hash(team)
22
- end
22
+ selected_team
23
+ end
23
24
 
24
- def self.update(path, args)
25
- team = info(path)
25
+ def create(org_name, args)
26
+ team = api.create_for_org(org_name, args)
26
27
 
27
- team = api.update(team[:id], args)
28
+ raise Sem::Errors::ResourceNotCreated.new("Team", [org_name, args[:name]]) if team.nil?
28
29
 
29
- to_hash(team)
30
- end
30
+ to_hash(team, org_name)
31
+ end
31
32
 
32
- def self.delete(path)
33
- id = info(path)[:id]
33
+ def update(org_name, team_name, args)
34
+ team = info(org_name, team_name)
34
35
 
35
- api.delete(id)
36
- end
36
+ team = api.update(team[:id], args)
37
37
 
38
- def self.api
39
- client.teams
40
- end
38
+ raise Sem::Errors::ResourceNotUpdated.new("Team", [org_name, team_name]) if team.nil?
39
+
40
+ to_hash(team, org_name)
41
+ end
42
+
43
+ def delete(org_name, team_name)
44
+ team = info(org_name, team_name)
45
+
46
+ api.delete!(team[:id])
47
+ rescue SemaphoreClient::Exceptions::RequestFailed
48
+ raise Sem::Errors::ResourceNotDeleted.new("Team", [org_name, team_name])
49
+ end
50
+
51
+ def api
52
+ client.teams
53
+ end
41
54
 
42
- def self.to_hash(team)
43
- {
44
- :id => team.id,
45
- :name => team.name,
46
- :permission => team.permission,
47
- :members => client.users.list_for_team(team.id).count.to_s,
48
- :created_at => team.created_at,
49
- :updated_at => team.updated_at
50
- }
55
+ def to_hash(team, org)
56
+ {
57
+ :id => team.id,
58
+ :name => team.name,
59
+ :org => org,
60
+ :permission => team.permission,
61
+ :members => client.users.list_for_team(team.id).to_a.size.to_s,
62
+ :created_at => team.created_at,
63
+ :updated_at => team.updated_at
64
+ }
65
+ end
51
66
  end
52
67
  end
53
68
  end
@@ -2,10 +2,14 @@ module Sem
2
2
  module API
3
3
  module Traits
4
4
  module AssociatedWithOrg
5
+ PAGES_PER_CALL = 3
6
+
5
7
  def list_for_org(org_name)
6
- instances = api.list_for_org(org_name)
8
+ pages = Sem::Pagination.pages(PAGES_PER_CALL) do |page_index|
9
+ api.list_for_org(org_name, :page => page_index).to_a
10
+ end
7
11
 
8
- instances.map { |instance| to_hash(instance) }
12
+ pages.flatten.pmap { |instance| to_hash(instance, org_name) }
9
13
  end
10
14
  end
11
15
  end
@@ -0,0 +1,29 @@
1
+ module Sem
2
+ module API
3
+ module Traits
4
+ module AssociatedWithProject
5
+ def list_for_project(org_name, project_name)
6
+ project = Projects.info(org_name, project_name)
7
+
8
+ instances = api.list_for_project(project[:id]).to_a
9
+
10
+ instances.map { |instance| to_hash(instance, org_name) }
11
+ end
12
+
13
+ def add_to_project(org_name, project_name, instance_name)
14
+ instance = info(org_name, instance_name)
15
+ project = Projects.info(org_name, project_name)
16
+
17
+ api.attach_to_project(instance[:id], project[:id])
18
+ end
19
+
20
+ def remove_from_project(org_name, project_name, instance_name)
21
+ instance = info(org_name, instance_name)
22
+ project = Projects.info(org_name, project_name)
23
+
24
+ api.detach_from_project(instance[:id], project[:id])
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,25 +2,27 @@ module Sem
2
2
  module API
3
3
  module Traits
4
4
  module AssociatedWithSharedConfig
5
- def list_for_shared_config(shared_config_path)
6
- shared_config = SharedConfigs.info(shared_config_path)
5
+ def list_for_shared_config(org_name, shared_config_name)
6
+ shared_config = SharedConfigs.info(org_name, shared_config_name)
7
7
 
8
- instances = api.list_for_shared_config(shared_config[:id])
8
+ instances = api.list_for_shared_config(shared_config[:id]).to_a
9
9
 
10
10
  instances.map { |instance| to_hash(instance) }
11
11
  end
12
12
 
13
- def add_to_shared_config(shared_config_path, params)
14
- shared_config = SharedConfigs.info(shared_config_path)
13
+ def add_to_shared_config(org_name, shared_config_name, params)
14
+ shared_config = SharedConfigs.info(org_name, shared_config_name)
15
15
 
16
16
  api.create_for_shared_config(shared_config[:id], params)
17
17
  end
18
18
 
19
- def remove_from_shared_config(shared_config_path, instance_name)
20
- instances = list_for_shared_config(shared_config_path)
19
+ def remove_from_shared_config(org_name, shared_config_name, instance_name)
20
+ instances = list_for_shared_config(org_name, shared_config_name)
21
21
 
22
22
  selected_instance = instances.find { |instance| instance[:name] == instance_name }
23
23
 
24
+ raise Sem::Errors::ResourceNotFound.new("Resource", [org_name, instance_name]) if selected_instance.nil?
25
+
24
26
  api.delete(selected_instance[:id])
25
27
  end
26
28
  end
@@ -2,26 +2,26 @@ module Sem
2
2
  module API
3
3
  module Traits
4
4
  module AssociatedWithTeam
5
- def list_for_team(team_path)
6
- team = Teams.info(team_path)
5
+ def list_for_team(org_name, team_name)
6
+ team_id = Teams.name_to_id(org_name, team_name)
7
7
 
8
- instances = api.list_for_team(team[:id])
8
+ instances = api.list_for_team(team_id).to_a
9
9
 
10
- instances.map { |instance| to_hash(instance) }
10
+ instances.map { |instance| to_hash(instance, org_name) }
11
11
  end
12
12
 
13
- def add_to_team(team_path, instance_path)
14
- instance = info(instance_path)
15
- team = Teams.info(team_path)
13
+ def add_to_team(org_name, team_name, instance_name)
14
+ instance_id = name_to_id(org_name, instance_name)
15
+ team_id = Teams.name_to_id(org_name, team_name)
16
16
 
17
- api.attach_to_team(instance[:id], team[:id])
17
+ api.attach_to_team(instance_id, team_id)
18
18
  end
19
19
 
20
- def remove_from_team(team_path, instance_path)
21
- instance = info(instance_path)
22
- team = Teams.info(team_path)
20
+ def remove_from_team(org_name, team_name, instance_name)
21
+ instance_id = name_to_id(org_name, instance_name)
22
+ team_id = Teams.name_to_id(org_name, team_name)
23
23
 
24
- api.detach_from_team(instance[:id], team[:id])
24
+ api.detach_from_team(instance_id, team_id)
25
25
  end
26
26
  end
27
27
  end
@@ -4,6 +4,7 @@ module Sem
4
4
  require_relative "traits/associated_with_org"
5
5
  require_relative "traits/associated_with_team"
6
6
  require_relative "traits/associated_with_shared_config"
7
+ require_relative "traits/associated_with_project"
7
8
  end
8
9
  end
9
10
  end