gocd 0.5 → 1.0

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