cyclid 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 +7 -0
- data/LICENSE +174 -0
- data/README.md +54 -0
- data/app/cyclid.rb +61 -0
- data/app/cyclid/config.rb +38 -0
- data/app/cyclid/controllers.rb +123 -0
- data/app/cyclid/controllers/auth.rb +34 -0
- data/app/cyclid/controllers/auth/token.rb +78 -0
- data/app/cyclid/controllers/health.rb +96 -0
- data/app/cyclid/controllers/organizations.rb +104 -0
- data/app/cyclid/controllers/organizations/collection.rb +134 -0
- data/app/cyclid/controllers/organizations/config.rb +128 -0
- data/app/cyclid/controllers/organizations/document.rb +135 -0
- data/app/cyclid/controllers/organizations/job.rb +266 -0
- data/app/cyclid/controllers/organizations/members.rb +145 -0
- data/app/cyclid/controllers/organizations/stages.rb +251 -0
- data/app/cyclid/controllers/users.rb +47 -0
- data/app/cyclid/controllers/users/collection.rb +131 -0
- data/app/cyclid/controllers/users/document.rb +133 -0
- data/app/cyclid/health_helpers.rb +40 -0
- data/app/cyclid/job.rb +3 -0
- data/app/cyclid/job/helpers.rb +67 -0
- data/app/cyclid/job/job.rb +164 -0
- data/app/cyclid/job/runner.rb +275 -0
- data/app/cyclid/job/stage.rb +67 -0
- data/app/cyclid/log_buffer.rb +104 -0
- data/app/cyclid/models.rb +3 -0
- data/app/cyclid/models/job_record.rb +25 -0
- data/app/cyclid/models/organization.rb +64 -0
- data/app/cyclid/models/plugin_config.rb +25 -0
- data/app/cyclid/models/stage.rb +42 -0
- data/app/cyclid/models/step.rb +29 -0
- data/app/cyclid/models/user.rb +60 -0
- data/app/cyclid/models/user_permissions.rb +28 -0
- data/app/cyclid/monkey_patches.rb +37 -0
- data/app/cyclid/plugin_registry.rb +75 -0
- data/app/cyclid/plugins.rb +125 -0
- data/app/cyclid/plugins/action.rb +48 -0
- data/app/cyclid/plugins/action/command.rb +89 -0
- data/app/cyclid/plugins/action/email.rb +207 -0
- data/app/cyclid/plugins/action/email/html.erb +58 -0
- data/app/cyclid/plugins/action/email/text.erb +13 -0
- data/app/cyclid/plugins/action/script.rb +90 -0
- data/app/cyclid/plugins/action/slack.rb +129 -0
- data/app/cyclid/plugins/action/slack/note.erb +5 -0
- data/app/cyclid/plugins/api.rb +195 -0
- data/app/cyclid/plugins/api/github.rb +111 -0
- data/app/cyclid/plugins/api/github/callback.rb +66 -0
- data/app/cyclid/plugins/api/github/methods.rb +201 -0
- data/app/cyclid/plugins/api/github/status.rb +67 -0
- data/app/cyclid/plugins/builder.rb +80 -0
- data/app/cyclid/plugins/builder/mist.rb +107 -0
- data/app/cyclid/plugins/dispatcher.rb +89 -0
- data/app/cyclid/plugins/dispatcher/local.rb +167 -0
- data/app/cyclid/plugins/provisioner.rb +40 -0
- data/app/cyclid/plugins/provisioner/debian.rb +90 -0
- data/app/cyclid/plugins/provisioner/ubuntu.rb +98 -0
- data/app/cyclid/plugins/source.rb +39 -0
- data/app/cyclid/plugins/source/git.rb +64 -0
- data/app/cyclid/plugins/transport.rb +63 -0
- data/app/cyclid/plugins/transport/ssh.rb +155 -0
- data/app/cyclid/sinatra/api_helpers.rb +66 -0
- data/app/cyclid/sinatra/auth_helpers.rb +127 -0
- data/app/cyclid/sinatra/warden/strategies/api_token.rb +62 -0
- data/app/cyclid/sinatra/warden/strategies/basic.rb +58 -0
- data/app/cyclid/sinatra/warden/strategies/hmac.rb +76 -0
- data/app/db.rb +51 -0
- data/bin/cyclid-db-init +107 -0
- data/db/schema.rb +92 -0
- data/lib/cyclid/app.rb +4 -0
- metadata +407 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require_rel 'github/methods'
|
17
|
+
require_rel 'github/status'
|
18
|
+
require_rel 'github/callback'
|
19
|
+
|
20
|
+
# Top level module for the core Cyclid code.
|
21
|
+
module Cyclid
|
22
|
+
# Module for the Cyclid API
|
23
|
+
module API
|
24
|
+
# Module for Cyclid Plugins
|
25
|
+
module Plugins
|
26
|
+
# API extension for Github hooks
|
27
|
+
class Github < Api
|
28
|
+
# Return an instance of the Github API controller
|
29
|
+
def self.controller
|
30
|
+
return ApiExtension::Controller.new(ApiExtension::GithubMethods)
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Merge the given config into the current config & validate
|
35
|
+
def update_config(config, new)
|
36
|
+
Cyclid.logger.debug "config=#{config} new=#{new}"
|
37
|
+
|
38
|
+
if new.key? 'repository_tokens'
|
39
|
+
Cyclid.logger.debug 'updating repository tokens'
|
40
|
+
|
41
|
+
new_tokens = new['repository_tokens']
|
42
|
+
current_tokens = config['repository_tokens']
|
43
|
+
|
44
|
+
raise 'repository_tokens must be an array' \
|
45
|
+
unless new_tokens.is_a? Array
|
46
|
+
|
47
|
+
# Merge the current list of tokens with the new list of tokens;
|
48
|
+
# we have to do this in a 'roundabout fashion:
|
49
|
+
#
|
50
|
+
# 1. Convert both into a hash, with the url as the key and
|
51
|
+
# the original hash itself as the value. E.g.
|
52
|
+
# {url: 'example.com', token: 'abcdef'} becomes
|
53
|
+
# {'exmaple.com': {url: 'example.com', token: 'abcdef'}}
|
54
|
+
# 2. Merge the new hash into the current hash; this will
|
55
|
+
# over-write any existing entries.
|
56
|
+
# 3. Obtain the values of the the resulting merged object, which
|
57
|
+
# is an array of the original hashes.
|
58
|
+
#
|
59
|
+
# Thanks, Stackoverflow!
|
60
|
+
new_hash = Hash[new_tokens.map{ |h| [h['url'], h] }]
|
61
|
+
current_hash = Hash[current_tokens.map{ |h| [h['url'], h] }]
|
62
|
+
|
63
|
+
merged = current_hash.merge(new_hash).values
|
64
|
+
|
65
|
+
# Delete any entries where the token value is nil
|
66
|
+
merged.delete_if do |entry|
|
67
|
+
entry['token'].nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
config['repository_tokens'] = merged
|
71
|
+
end
|
72
|
+
|
73
|
+
if new.key? 'hmac_secret'
|
74
|
+
Cyclid.logger.debug 'updating HMAC secret'
|
75
|
+
config['hmac_secret'] = new['hmac_secret']
|
76
|
+
end
|
77
|
+
|
78
|
+
return config
|
79
|
+
end
|
80
|
+
|
81
|
+
# Default configuration
|
82
|
+
def default_config
|
83
|
+
config = {}
|
84
|
+
config['repository_tokens'] = []
|
85
|
+
config['hmac_secret'] = nil
|
86
|
+
|
87
|
+
return config
|
88
|
+
end
|
89
|
+
|
90
|
+
# Github plugin configuration schema
|
91
|
+
def config_schema
|
92
|
+
schema = []
|
93
|
+
schema << { name: 'repository_tokens',
|
94
|
+
type: 'hash-list',
|
95
|
+
description: 'Repository OAuth tokens',
|
96
|
+
default: [] }
|
97
|
+
schema << { name: 'hmac_secret',
|
98
|
+
type: 'string',
|
99
|
+
description: 'Github HMAC signing secret',
|
100
|
+
default: nil }
|
101
|
+
|
102
|
+
return schema
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Register this plugin
|
107
|
+
register_plugin 'github'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Container for the Sinatra related controllers modules
|
23
|
+
module ApiExtension
|
24
|
+
# Notifier callback for Github. Updates the external Github Pull
|
25
|
+
# Request status as the job progresses.
|
26
|
+
class GithubCallback < Plugins::Notifier::Callback
|
27
|
+
def initialize(statuses, auth_token)
|
28
|
+
@statuses = statuses
|
29
|
+
@auth_token = auth_token
|
30
|
+
end
|
31
|
+
|
32
|
+
# Job status has changed
|
33
|
+
def status_changed(job_id, status)
|
34
|
+
case status
|
35
|
+
when Constants::JobStatus::WAITING
|
36
|
+
state = 'pending'
|
37
|
+
message = "Queued job ##{job_id}."
|
38
|
+
when Constants::JobStatus::STARTED
|
39
|
+
state = 'pending'
|
40
|
+
message = "Job ##{job_id} started."
|
41
|
+
when Constants::JobStatus::FAILING
|
42
|
+
state = 'failure'
|
43
|
+
message = "Job ##{job_id} failed. Waiting for job to complete."
|
44
|
+
else
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
GithubStatus.set_status(@statuses, @auth_token, state, message)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Job has completed
|
52
|
+
def completion(job_id, status)
|
53
|
+
if status == true
|
54
|
+
state = 'success'
|
55
|
+
message = "Job ##{job_id} completed successfuly."
|
56
|
+
else
|
57
|
+
state = 'failure'
|
58
|
+
message = "Job ##{job_id} failed."
|
59
|
+
end
|
60
|
+
GithubStatus.set_status(@statuses, @auth_token, state, message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Container for the Sinatra related controllers modules
|
23
|
+
module ApiExtension
|
24
|
+
# Github plugin method callbacks
|
25
|
+
module GithubMethods
|
26
|
+
include Methods
|
27
|
+
|
28
|
+
# Return a reference to the plugin that is associated with this
|
29
|
+
# controller; used by the lower level code.
|
30
|
+
def controller_plugin
|
31
|
+
Cyclid.plugins.find('github', Cyclid::API::Plugins::Api)
|
32
|
+
end
|
33
|
+
|
34
|
+
# HTTP POST callback
|
35
|
+
def post(data, headers, config)
|
36
|
+
return_failure(400, 'no event specified') \
|
37
|
+
unless headers.include? 'X-Github-Event'
|
38
|
+
|
39
|
+
return_failure(400, 'no delivery ID specified') \
|
40
|
+
unless headers.include? 'X-Github-Delivery'
|
41
|
+
|
42
|
+
event = headers['X-Github-Event']
|
43
|
+
# Not used yet but will be when we add HMAC support
|
44
|
+
# signature = headers['X-Hub-Signature'] || nil
|
45
|
+
|
46
|
+
Cyclid.logger.debug "Github: event is #{event}"
|
47
|
+
|
48
|
+
case event
|
49
|
+
when 'pull_request'
|
50
|
+
result = gh_pull_request(data, config)
|
51
|
+
when 'ping'
|
52
|
+
result = true
|
53
|
+
when 'status'
|
54
|
+
result = true
|
55
|
+
else
|
56
|
+
return_failure(400, "event type '#{event}' is not supported")
|
57
|
+
end
|
58
|
+
|
59
|
+
return result
|
60
|
+
end
|
61
|
+
|
62
|
+
# Handle a Github Pull Request event
|
63
|
+
def gh_pull_request(data, config)
|
64
|
+
action = data['action'] || nil
|
65
|
+
pr = data['pull_request'] || nil
|
66
|
+
|
67
|
+
Cyclid.logger.debug "action=#{action}"
|
68
|
+
return true unless action == 'opened' \
|
69
|
+
or action == 'reopened' \
|
70
|
+
or action == 'synchronize'
|
71
|
+
|
72
|
+
# Get the list of files in the root of the repository in the
|
73
|
+
# Pull Request branch
|
74
|
+
html_url = URI(pr['base']['repo']['html_url'])
|
75
|
+
pr_sha = pr['head']['sha']
|
76
|
+
ref = pr['head']['ref']
|
77
|
+
|
78
|
+
Cyclid.logger.debug "sha=#{pr_sha} ref=#{ref}"
|
79
|
+
|
80
|
+
# Get some useful endpoints & interpolate the SHA for this PR
|
81
|
+
url = pr['head']['repo']['statuses_url']
|
82
|
+
statuses = url.gsub('{sha}', pr_sha)
|
83
|
+
|
84
|
+
url = pr['head']['repo']['trees_url']
|
85
|
+
trees = url.gsub('{/sha}', "/#{pr_sha}")
|
86
|
+
|
87
|
+
# Get an OAuth token, if one is set for this repo
|
88
|
+
Cyclid.logger.debug "attempting to find auth token for #{html_url}"
|
89
|
+
auth_token = nil
|
90
|
+
config['repository_tokens'].each do |entry|
|
91
|
+
entry_url = URI(entry['url'])
|
92
|
+
auth_token = entry['token'] if entry_url.host == html_url.host && \
|
93
|
+
entry_url.path == html_url.path
|
94
|
+
end
|
95
|
+
|
96
|
+
# XXX We probably don't want to be logging auth tokens in plain text
|
97
|
+
Cyclid.logger.debug "auth token=#{auth_token}"
|
98
|
+
|
99
|
+
# Set the PR to 'pending'
|
100
|
+
GithubStatus.set_status(statuses, auth_token, 'pending', 'Preparing build')
|
101
|
+
|
102
|
+
# Get the Pull Request
|
103
|
+
begin
|
104
|
+
trees_url = URI(trees)
|
105
|
+
Cyclid.logger.debug "Getting root for #{trees_url}"
|
106
|
+
|
107
|
+
request = Net::HTTP::Get.new(trees_url)
|
108
|
+
request.add_field('Authorization', "token #{auth_token}") \
|
109
|
+
unless auth_token.nil?
|
110
|
+
|
111
|
+
http = Net::HTTP.new(trees_url.hostname, trees_url.port)
|
112
|
+
http.use_ssl = (trees_url.scheme == 'https')
|
113
|
+
response = http.request(request)
|
114
|
+
|
115
|
+
Cyclid.logger.debug response.inspect
|
116
|
+
raise "couldn't get repository root" \
|
117
|
+
unless response.code == '200'
|
118
|
+
|
119
|
+
root = Oj.load response.body
|
120
|
+
rescue StandardError => ex
|
121
|
+
Cyclid.logger.error "failed to retrieve Pull Request root: #{ex}"
|
122
|
+
return_failure(500, 'could not retrieve Pull Request root')
|
123
|
+
end
|
124
|
+
|
125
|
+
# See if a .cyclid.yml or .cyclid.json file exists in the project
|
126
|
+
# root
|
127
|
+
job_url = nil
|
128
|
+
job_type = nil
|
129
|
+
root['tree'].each do |file|
|
130
|
+
match = file['path'].match(/\A\.cyclid\.(json|yml)\z/)
|
131
|
+
next unless match
|
132
|
+
|
133
|
+
job_url = URI(file['url'])
|
134
|
+
job_type = match[1]
|
135
|
+
end
|
136
|
+
|
137
|
+
Cyclid.logger.debug "job_url=#{job_url}"
|
138
|
+
|
139
|
+
if job_url.nil?
|
140
|
+
GithubStatus.set_status(statuses, auth_token, 'error', 'No Cyclid job file found')
|
141
|
+
return_failure(400, 'not a Cyclid repository')
|
142
|
+
end
|
143
|
+
|
144
|
+
# Pull down the job file
|
145
|
+
begin
|
146
|
+
Cyclid.logger.info "Retrieving PR job from #{job_url}"
|
147
|
+
|
148
|
+
request = Net::HTTP::Get.new(job_url)
|
149
|
+
request.add_field('Authorization', "token #{auth_token}") \
|
150
|
+
unless auth_token.nil?
|
151
|
+
|
152
|
+
http = Net::HTTP.new(job_url.hostname, job_url.port)
|
153
|
+
http.use_ssl = (job_url.scheme == 'https')
|
154
|
+
response = http.request(request)
|
155
|
+
raise "couldn't get Cyclid job" unless response.code == '200'
|
156
|
+
|
157
|
+
job_blob = Oj.load response.body
|
158
|
+
case job_type
|
159
|
+
when 'json'
|
160
|
+
job_definition = Oj.load(Base64.decode64(job_blob['content']))
|
161
|
+
when 'yml'
|
162
|
+
job_definition = YAML.load(Base64.decode64(job_blob['content']))
|
163
|
+
end
|
164
|
+
|
165
|
+
# Insert this repository & branch into the sources
|
166
|
+
#
|
167
|
+
# XXX Could this cause collisions between the existing sources in
|
168
|
+
# the job definition? Not entirely sure what the workflow will
|
169
|
+
# look like.
|
170
|
+
job_sources = job_definition['sources'] || []
|
171
|
+
job_sources << { 'type' => 'git',
|
172
|
+
'url' => html_url.to_s,
|
173
|
+
'branch' => ref,
|
174
|
+
'token' => auth_token }
|
175
|
+
job_definition['sources'] = job_sources
|
176
|
+
|
177
|
+
Cyclid.logger.debug "sources=#{job_definition['sources']}"
|
178
|
+
rescue StandardError => ex
|
179
|
+
GithubStatus.set_status(statuses,
|
180
|
+
auth_token,
|
181
|
+
'error',
|
182
|
+
"Couldn't retrieve Cyclid job file")
|
183
|
+
Cyclid.logger.error "failed to retrieve Github Pull Request job: #{ex}"
|
184
|
+
raise
|
185
|
+
end
|
186
|
+
|
187
|
+
Cyclid.logger.debug "job_definition=#{job_definition}"
|
188
|
+
|
189
|
+
begin
|
190
|
+
callback = GithubCallback.new(statuses, auth_token)
|
191
|
+
job_from_definition(job_definition, callback)
|
192
|
+
rescue StandardError => ex
|
193
|
+
GithubStatus.set_status(statuses, auth_token, 'failure', ex)
|
194
|
+
return_failure(500, 'job failed')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'net/http'
|
17
|
+
|
18
|
+
# Top level module for the core Cyclid code.
|
19
|
+
module Cyclid
|
20
|
+
# Module for the Cyclid API
|
21
|
+
module API
|
22
|
+
# Module for Cyclid Plugins
|
23
|
+
module Plugins
|
24
|
+
# Container for the Sinatra related controllers modules
|
25
|
+
module ApiExtension
|
26
|
+
# Wrapper for a static method to push a status update to Github
|
27
|
+
module GithubStatus
|
28
|
+
# Call the Github statuses API to update the status
|
29
|
+
def self.set_status(statuses, auth_token, state, description)
|
30
|
+
# Update the PR status
|
31
|
+
|
32
|
+
statuses_url = URI(statuses)
|
33
|
+
status = { state: state,
|
34
|
+
target_url: 'http://cyclid.io',
|
35
|
+
description: description,
|
36
|
+
context: 'continuous-integration/cyclid' }
|
37
|
+
|
38
|
+
# Post the status to the statuses endpoint
|
39
|
+
request = Net::HTTP::Post.new(statuses_url)
|
40
|
+
request.content_type = 'application/json'
|
41
|
+
request.add_field 'Authorization', "token #{auth_token}" \
|
42
|
+
unless auth_token.nil?
|
43
|
+
request.body = status.to_json
|
44
|
+
|
45
|
+
http = Net::HTTP.new(statuses_url.hostname, statuses_url.port)
|
46
|
+
http.use_ssl = (statuses_url.scheme == 'https')
|
47
|
+
response = http.request(request)
|
48
|
+
|
49
|
+
case response
|
50
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
51
|
+
Cyclid.logger.info "updated PR status to #{state}"
|
52
|
+
when Net::HTTPNotFound
|
53
|
+
Cyclid.logger.error 'update PR status failed; possibly an auth failure'
|
54
|
+
raise
|
55
|
+
else
|
56
|
+
Cyclid.logger.error "update PR status failed: #{response}"
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
rescue StandardError => ex
|
60
|
+
Cyclid.logger.error "couldn't set status for PR: #{ex}"
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Base class for BuildHost
|
23
|
+
class BuildHost < Hash
|
24
|
+
def initialize(args)
|
25
|
+
args.each do |key, value|
|
26
|
+
self[key.to_sym] = value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the information needed (hostname/IP, username, password & key
|
31
|
+
# if there are any) to create a Transport to this host, in a normalized form.
|
32
|
+
def connect_info
|
33
|
+
[self[:host], self[:username], self[:password], self[:key]]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return a list of acceptable Transports that can be used to connect to this
|
37
|
+
# host.
|
38
|
+
def transports
|
39
|
+
# XXX Maybe create some constants for "well known" Transports such as 'ssh'
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return free-form data about this host that may be useful to the build
|
44
|
+
# process and can be merged into the Job context. This may be a subset of the
|
45
|
+
# data for this BuildHost, or the full set.
|
46
|
+
def context_info
|
47
|
+
dup
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Base class for Builders
|
52
|
+
class Builder < Base
|
53
|
+
# Create a build host, probably on a remote system, and return information
|
54
|
+
# about it in a BuildHost object that encapsulates the information about it.
|
55
|
+
def initialize(*args)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the 'human' name for the plugin type
|
59
|
+
def self.human_name
|
60
|
+
'builder'
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get or create a build host that can be used by a job. Args will be things
|
64
|
+
# like the OS & version required, taken from the 'environment' section of the
|
65
|
+
# job definition.
|
66
|
+
#
|
67
|
+
# The Builder can call out to external service E.g. AWS, DO, RAX etc. or
|
68
|
+
# return an existing instance from a pool
|
69
|
+
def get(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Shut down/release/destroy (if appropriate) the build host
|
73
|
+
def release(_transport, _buildhost)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
require_rel 'builder/*.rb'
|