gocd 0.5 → 1.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +34 -1
  6. data/LICENSE.txt +201 -0
  7. data/README.md +71 -0
  8. data/Rakefile +7 -0
  9. data/gocd.gemspec +3 -0
  10. data/lib/gocd/agents/agent.rb +1 -1
  11. data/lib/gocd/agents/agents_repository.rb +1 -1
  12. data/lib/gocd/config/credentials.rb +2 -0
  13. data/lib/gocd/history/history_fetcher.rb +35 -0
  14. data/lib/gocd/pipeline_config/environment.rb +29 -0
  15. data/lib/gocd/pipeline_config/job.rb +21 -0
  16. data/lib/gocd/pipeline_config/pipeline.rb +30 -0
  17. data/lib/gocd/pipeline_config/pipeline_config.rb +72 -0
  18. data/lib/gocd/pipeline_config/pipeline_group.rb +20 -0
  19. data/lib/gocd/pipeline_config/repository/pipeline_config_repository.rb +11 -0
  20. data/lib/gocd/pipeline_config/stage.rb +26 -0
  21. data/lib/gocd/pipeline_config/template.rb +6 -0
  22. data/lib/gocd/{pipeline → pipeline_status}/pipeline.rb +0 -0
  23. data/lib/gocd/{pipeline → pipeline_status}/pipeline_repository.rb +0 -0
  24. data/lib/gocd/{pipeline → pipeline_status}/pipelines.rb +0 -0
  25. data/lib/gocd/version.rb +1 -1
  26. data/spec/gocd/agents/agent_spec.rb +98 -0
  27. data/spec/gocd/agents/agents_repository_spec.rb +79 -0
  28. data/spec/gocd/agents/agents_spec.rb +37 -0
  29. data/spec/gocd/config/credentials_spec.rb +9 -0
  30. data/spec/gocd/history/history_fetcher_spec.rb +54 -0
  31. data/spec/gocd/pipeline_config/environment_spec.rb +27 -0
  32. data/spec/gocd/pipeline_config/job_spec.rb +23 -0
  33. data/spec/gocd/pipeline_config/pipeline_group_spec.rb +50 -0
  34. data/spec/gocd/pipeline_config/pipeline_spec.rb +62 -0
  35. data/spec/gocd/pipeline_config/stage_spec.rb +32 -0
  36. data/spec/gocd/pipeline_config/template_spec.rb +32 -0
  37. data/spec/gocd/pipeline_status/pipeline_spec.rb +47 -0
  38. data/spec/gocd/pipeline_status/pipelines_repository_spec.rb +43 -0
  39. data/spec/gocd/pipeline_status/pipelines_spec.rb +80 -0
  40. data/spec/spec_helper.rb +103 -0
  41. metadata +91 -5
@@ -0,0 +1,21 @@
1
+ require_relative './pipeline_config'
2
+
3
+ module GOCD
4
+ module PIPELINE_CONFIG
5
+ class Job
6
+ include GOCD::PIPELINE_CONFIG
7
+ attr_reader :pipeline, :stage, :name, :resources
8
+
9
+ def initialize(pipeline, stage, data)
10
+ @pipeline = pipeline
11
+ @stage = stage
12
+ @name = data['name']
13
+ @resources = data['resources'].nil? ? [] : to_array(data['resources']['resource'])
14
+ end
15
+
16
+ def pipeline=(new_name)
17
+ @pipeline = new_name
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require_relative './stage'
2
+
3
+ module GOCD
4
+ module PIPELINE_CONFIG
5
+ class Pipeline
6
+ include GOCD::PIPELINE_CONFIG
7
+ attr_reader :name, :stages, :template
8
+
9
+ def initialize(data)
10
+ @template = data['template']
11
+ @name = data['name']
12
+ @stages = to_stages(data['stage']) || []
13
+ end
14
+
15
+ def has_template?
16
+ !template.nil?
17
+ end
18
+
19
+ def name=(new_name)
20
+ @name = new_name
21
+ @stages.each { |stage| stage.pipeline = new_name }
22
+ end
23
+
24
+ private
25
+ def to_stages(data)
26
+ to_array(data).map { |stage| GOCD::PIPELINE_CONFIG::Stage.new(name, stage) } unless data.nil?
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,72 @@
1
+ require_relative './environment'
2
+ require_relative './pipeline_group'
3
+ require_relative './pipeline'
4
+ require_relative './repository/pipeline_config_repository'
5
+
6
+ module GOCD
7
+ module PIPELINE_CONFIG
8
+ @config_response = nil
9
+
10
+ def environments
11
+ raw_environments = to_array(pipeline_config_response["cruise"]["environments"]["environment"])
12
+ environments = raw_environments.map do |environment|
13
+ GOCD::PIPELINE_CONFIG::Environment.new(environment)
14
+ end
15
+
16
+ add_pipelines_to_environments environments, pipelines
17
+ environments
18
+ end
19
+
20
+ def pipelines
21
+ pipelines = groups.map { |group| group.pipelines }.flatten
22
+ merge_pipelines_with_templates pipelines, templates
23
+ end
24
+
25
+ def templates
26
+ raw_templates = to_array(pipeline_config_response["cruise"]["templates"]["pipeline"])
27
+ raw_templates.map { |template| GOCD::PIPELINE_CONFIG::Template.new(template) }
28
+ end
29
+
30
+ def groups
31
+ raw_groups = to_array(pipeline_config_response['cruise']['pipelines'])
32
+ raw_groups.map do |group|
33
+ GOCD::PIPELINE_CONFIG::PipelineGroup.new(group)
34
+ end
35
+ end
36
+
37
+ def pipeline_config_response
38
+ @config_response ||= PipelineConfigRepository.fetch_config
39
+ end
40
+
41
+ def to_array(data)
42
+ [data].compact.flatten
43
+ end
44
+
45
+ private
46
+ def add_pipelines_to_environments(environments, pipelines)
47
+ environments.each do |environment|
48
+ pipelines_for_env = []
49
+ environment.pipeline_names.each do |pipeline|
50
+ pipelines_for_env << pipelines.select { |p| p.name == pipeline }
51
+ end
52
+ environment.enrich_with_pipelines pipelines_for_env.flatten.compact
53
+ end
54
+ end
55
+
56
+ def merge_pipelines_with_templates(pipelines, templates)
57
+ pipeline_with_templates = pipelines.select { |p| p.has_template? }
58
+ standalone_pipelines = pipelines - pipeline_with_templates
59
+
60
+ pipelines_merged_with_templates = pipeline_with_templates.map do |pwt|
61
+ matched_template = templates.select { |t| t.name.upcase == pwt.template.upcase }
62
+ if matched_template.size > 0
63
+ matched_template.first.name = pwt.name
64
+ matched_template
65
+ else
66
+ pwt
67
+ end
68
+ end
69
+ [standalone_pipelines + pipelines_merged_with_templates].flatten.compact
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,20 @@
1
+ require_relative './pipeline'
2
+
3
+ module GOCD
4
+ module PIPELINE_CONFIG
5
+ class PipelineGroup
6
+ include GOCD::PIPELINE_CONFIG
7
+ attr_reader :name, :pipelines
8
+
9
+ def initialize(group_data)
10
+ @name = group_data['group']
11
+ @pipelines = to_pipelines(group_data['pipeline']) || []
12
+ end
13
+
14
+ private
15
+ def to_pipelines(pipelines_data)
16
+ to_array(pipelines_data).map { |pipeline| GOCD::PIPELINE_CONFIG::Pipeline.new(pipeline) } unless pipelines_data.nil?
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require 'active_support/core_ext/hash/conversions'
2
+
3
+ module GOCD
4
+ module PIPELINE_CONFIG
5
+ class PipelineConfigRepository
6
+ def self.fetch_config
7
+ Hash.from_xml(`curl -s -k -u #{GOCD.credentials.curl_credentials} #{GOCD.server.url}/go/api/admin/config/current.xml`)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require_relative './job'
2
+
3
+ module GOCD
4
+ module PIPELINE_CONFIG
5
+ class Stage
6
+ include GOCD::PIPELINE_CONFIG
7
+ attr_reader :pipeline, :name, :jobs
8
+
9
+ def initialize(pipeline, data)
10
+ @pipeline = pipeline
11
+ @name = data['name']
12
+ @jobs = data['jobs'].nil? ? [] : to_jobs(data['jobs']['job'])
13
+ end
14
+
15
+ def pipeline=(new_name)
16
+ @pipeline = new_name
17
+ @jobs.each { |job| job.pipeline = new_name }
18
+ end
19
+
20
+ private
21
+ def to_jobs(data)
22
+ to_array(data).map { |job| GOCD::PIPELINE_CONFIG::Job.new(pipeline, name, job) }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ module GOCD
2
+ module PIPELINE_CONFIG
3
+ class Template < Pipeline
4
+ end
5
+ end
6
+ end
@@ -1,3 +1,3 @@
1
1
  module GOCD
2
- VERSION = '0.5'
2
+ VERSION = '1.0'
3
3
  end
@@ -0,0 +1,98 @@
1
+ require './lib/gocd/agents/agent'
2
+
3
+ RSpec.describe GOCD::Agent, 'agent' do
4
+
5
+ agent_response = {
6
+ 'hostname' => 'agent 1',
7
+ 'uuid' => '1a2s3d4f',
8
+ 'operating_system' => 'Linux',
9
+ 'free_space' => 76202504192,
10
+ 'agent_state' => 'Idle',
11
+ 'resources' => %w(java automation),
12
+ 'environments' => %w(iOS android),
13
+ 'sandbox' => '/Applications/GoAgent.app',
14
+ 'agent_config_state' => 'Disabled',
15
+ 'ip_address' => '10.0.0.1'
16
+ }
17
+
18
+ context 'agent getters' do
19
+ before(:each) do
20
+ @agent = GOCD::Agent.new agent_response
21
+ end
22
+
23
+ it '#name should return agent name' do
24
+ expect(@agent.name).to eq 'agent 1'
25
+ end
26
+
27
+ it '#uuid should return agent uuid' do
28
+ expect(@agent.uuid).to eq '1a2s3d4f'
29
+ end
30
+
31
+ it '#os should return agent operating system' do
32
+ expect(@agent.os).to eq 'Linux'
33
+ end
34
+
35
+ it '#free_space should return free space on agent' do
36
+ expect(@agent.free_space).to eq 76202504192
37
+ end
38
+
39
+ it '#state should return agent state' do
40
+ expect(@agent.state).to eq 'Idle'
41
+ end
42
+
43
+ it '#resources should return agent resources' do
44
+ expect(@agent.resources).to eq %w(java automation)
45
+ end
46
+
47
+ it '#has_resource should return true when agent has given resource' do
48
+ expect(@agent.has_resource 'java').to be_truthy
49
+ end
50
+
51
+ it '#has_resource should return false when agent does not have given resource' do
52
+ expect(@agent.has_resource 'abcd').to be_falsy
53
+ end
54
+
55
+ it '#environments should return agent environments' do
56
+ expect(@agent.environments).to eq %w(iOS android)
57
+ end
58
+
59
+ it '#has_environment should return true when agent has given environment' do
60
+ expect(@agent.has_environment 'iOS').to be_truthy
61
+ end
62
+
63
+ it '#has_environment should return false when agent does not have given environment' do
64
+ expect(@agent.has_environment 'abcd').to be_falsy
65
+ end
66
+
67
+ it '#location should return agent sandbox location' do
68
+ expect(@agent.location).to eq '/Applications/GoAgent.app'
69
+ end
70
+
71
+ it '#idle? should return true when agent is Idle' do
72
+ expect(@agent.idle?).to be_truthy
73
+ end
74
+
75
+ it '#building? should return true when agent is Building' do
76
+ agent_response['agent_state'] = 'Building'
77
+ @agent = GOCD::Agent.new agent_response
78
+ expect(@agent.building?).to be_truthy
79
+ end
80
+
81
+ it '#missing? should return true when agent is Missing' do
82
+ agent_response['agent_state'] = 'Missing'
83
+ @agent = GOCD::Agent.new agent_response
84
+ expect(@agent.missing?).to be_truthy
85
+ end
86
+
87
+ it '#disabled? should return true when agent is disabled' do
88
+ expect(@agent.disabled?).to be_truthy
89
+ end
90
+
91
+ it '#disabled? should return false when agent is not disabled' do
92
+ agent_response['agent_config_state'] = 'Running'
93
+ @agent = GOCD::Agent.new agent_response
94
+ expect(@agent.disabled?).to be_falsy
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,79 @@
1
+ require_relative '../../../lib/gocd/agents/agents_repository'
2
+ require_relative '../../../lib/gocd/config/credentials'
3
+ require_relative '../../../lib/gocd/config/server'
4
+ require_relative '../../../lib/gocd/exception/data_fetch_exception'
5
+
6
+
7
+ def setup_credential_and_server
8
+ GOCD.credentials = GOCD::Credentials.new 'admin', 'password'
9
+ GOCD.server = GOCD::Server.new 'http://gocd.com'
10
+ end
11
+
12
+ RSpec.describe GOCD::AgentRepository, 'agent' do
13
+
14
+ response_json = '{
15
+ "_embedded": {
16
+ "agents": [
17
+ {
18
+ "uuid": "1q2w3e4r",
19
+ "hostname": "agent 1",
20
+ "ip_address": "10.131.2.150",
21
+ "sandbox": "/Applications/GoAgent.app",
22
+ "operating_system": "Mac OS X",
23
+ "free_space": 76202508288,
24
+ "agent_config_state": "Enabled",
25
+ "agent_state": "Idle",
26
+ "build_state": "Idle",
27
+ "resources": [
28
+ "java",
29
+ "automation"
30
+ ],
31
+ "environments": [
32
+ "Automation",
33
+ "iOS"
34
+ ]
35
+ },
36
+ {
37
+ "uuid": "0p9o8i7u",
38
+ "hostname": "agent 2",
39
+ "ip_address": "10.131.2.150",
40
+ "sandbox": "/Applications/GoAgent.app.2",
41
+ "operating_system": "Mac OS X",
42
+ "free_space": 76202504192,
43
+ "agent_config_state": "Enabled",
44
+ "agent_state": "Idle",
45
+ "build_state": "Idle",
46
+ "resources": [
47
+ "promotion"
48
+ ],
49
+ "environments": [
50
+ "iOS"
51
+ ]
52
+ }
53
+ ]
54
+ }
55
+ }'
56
+
57
+ it '#agents should return all agent' do
58
+ setup_credential_and_server
59
+ curl_command = "curl -s -k -u admin:password http://gocd.com/go/api/agents -H 'Accept: application/vnd.go.cd.v4+json'"
60
+ expect(GOCD::AgentRepository).to receive(:`).with(curl_command).and_return(response_json)
61
+
62
+ agents = GOCD::AgentRepository.agents
63
+ expect(agents.size).to eq 2
64
+ expect(agents[0].name).to eq 'agent 1'
65
+ expect(agents[0].uuid).to eq '1q2w3e4r'
66
+ expect(agents[1].name).to eq 'agent 2'
67
+ expect(agents[1].uuid).to eq '0p9o8i7u'
68
+
69
+ end
70
+
71
+ it '#agents should raise GOCDDataFetchException exception' do
72
+ GOCD::AgentRepository.instance_variable_set(:@agents, nil)
73
+ setup_credential_and_server
74
+ curl_command = "curl -s -k -u admin:password http://gocd.com/go/api/agents -H 'Accept: application/vnd.go.cd.v4+json'"
75
+ expect(GOCD::AgentRepository).to receive(:`).with(curl_command).and_return(nil)
76
+
77
+ expect{GOCD::AgentRepository.agents}.to raise_error(GOCDDataFetchException).with_message('Could not fetch data from server!!')
78
+ end
79
+ end
@@ -0,0 +1,37 @@
1
+ require './lib/gocd/agents/agents'
2
+ require_relative '../../../lib/gocd/agents/agents_repository'
3
+
4
+
5
+ RSpec.describe GOCD::Agents, 'agents' do
6
+
7
+ context 'All Agents' do
8
+
9
+ it '#idle should filter out idle agents' do
10
+ agent1 = instance_double('agent', :idle? => true)
11
+ agent2 = instance_double('agent', :idle? => false)
12
+ expect(GOCD::Agents).to receive(:agents).and_return([agent1, agent2])
13
+ expect(GOCD::Agents.idle.size).to eq 1
14
+ end
15
+
16
+ it '#idle should filter out missing agents' do
17
+ agent1 = instance_double('agent', :missing? => true)
18
+ agent2 = instance_double('agent', :missing? => false)
19
+ expect(GOCD::Agents).to receive(:agents).and_return([agent1, agent2])
20
+ expect(GOCD::Agents.missing.size).to eq 1
21
+ end
22
+
23
+ it '#idle should filter out agents in building state' do
24
+ agent1 = instance_double('agent', :building? => true)
25
+ agent2 = instance_double('agent', :building? => false)
26
+ expect(GOCD::Agents).to receive(:agents).and_return([agent1, agent2])
27
+ expect(GOCD::Agents.building.size).to eq 1
28
+ end
29
+
30
+ it '#idle should filter out disabled agents' do
31
+ agent1 = instance_double('agent', :disabled? => true)
32
+ agent2 = instance_double('agent', :disabled? => false)
33
+ expect(GOCD::Agents).to receive(:agents).and_return([agent1, agent2])
34
+ expect(GOCD::Agents.disabled.size).to eq 1
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ require './lib/gocd/config/credentials'
2
+
3
+ RSpec.describe GOCD::Credentials, 'credentials' do
4
+
5
+ it '#curl_credentials should return credentials' do
6
+ credentials = GOCD::Credentials.new 'admin', 'password'
7
+ expect(credentials.curl_credentials).to eq 'admin:password'
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../../../lib/gocd/history/history_fetcher'
2
+ require_relative '../../../lib/gocd/config/credentials'
3
+ require_relative '../../../lib/gocd/config/server'
4
+ require_relative '../../../lib/gocd/pipeline_config/job'
5
+ require 'rest-client'
6
+ require 'ostruct'
7
+
8
+ def setup_credential_and_server
9
+ GOCD.credentials = GOCD::Credentials.new 'admin', 'password'
10
+ GOCD.server = GOCD::Server.new 'http://gocd.com'
11
+ end
12
+
13
+ RSpec.describe GOCD::HistoryFetcher, 'history' do
14
+
15
+ response = "cruise_agent,cruise_job_duration,cruise_job_id,cruise_job_result,cruise_pipeline_counter,cruise_pipeline_label,cruise_stage_counter,cruise_timestamp_01_scheduled,cruise_timestamp_02_assigned,cruise_timestamp_03_preparing,cruise_timestamp_04_building,cruise_timestamp_05_completing,cruise_timestamp_06_completed,tests_failed_count,tests_ignored_count,tests_total_count,tests_total_duration\nAgent1,320,826882,Passed,10314,pipe-10314-job-5621,1,2017-02-23T14:49:17Z,2017-02-23T14:49:22Z,2017-02-23T14:49:33Z,2017-02-23T14:49:41Z,2017-02-23T14:54:39Z,2017-02-23T14:55:02Z,0,0,4218,84.882\n"
16
+ job = GOCD::PIPELINE_CONFIG::Job.new('Pipeline', 'stage', {'name' => 'job'})
17
+
18
+ before(:each) do
19
+ setup_credential_and_server
20
+ params = "pipelineName=#{job.pipeline}&stageName=#{job.stage}&jobName=#{job.name}&limitPipeline=latest&limitCount=#{1}"
21
+ request = {
22
+ method: :get,
23
+ url: "http://gocd.com/go/properties/search?#{params}",
24
+ user: 'admin',
25
+ password: 'password',
26
+ }
27
+ expect(RestClient::Request).to receive(:execute).with(request).and_return(OpenStruct.new({body: response}))
28
+ end
29
+
30
+ it 'should fetch history of a job' do
31
+ histories = GOCD::HistoryFetcher.fetch_job_history(job, 1)
32
+
33
+ expect(histories.size).to eq 1
34
+ history = histories.first
35
+ expect(history['cruise_agent']).to eq 'Agent1'
36
+ expect(history['cruise_job_duration']).to eq '320'
37
+ expect(history['cruise_job_id']).to eq '826882'
38
+ expect(history['cruise_job_result']).to eq 'Passed'
39
+ expect(history['cruise_pipeline_counter']).to eq '10314'
40
+ expect(history['cruise_pipeline_label']).to eq 'pipe-10314-job-5621'
41
+ expect(history['cruise_stage_counter']).to eq '1'
42
+ expect(history['cruise_timestamp_01_scheduled']).to eq '2017-02-23T14:49:17Z'
43
+ expect(history['cruise_timestamp_02_assigned']).to eq '2017-02-23T14:49:22Z'
44
+ expect(history['cruise_timestamp_04_building']).to eq '2017-02-23T14:49:41Z'
45
+ expect(history['cruise_timestamp_05_completing']).to eq '2017-02-23T14:54:39Z'
46
+ expect(history['cruise_timestamp_06_completed']).to eq '2017-02-23T14:55:02Z'
47
+ end
48
+
49
+ it 'should fetch raw history of a job' do
50
+ histories = GOCD::HistoryFetcher.fetch_raw_job_history(job, 1)
51
+
52
+ expect(histories).to eq response
53
+ end
54
+ end