cyclid 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,134 @@
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 'octokit'
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
+ # Github plugin method callbacks
27
+ module GithubMethods
28
+ # Handle a Pull Request event
29
+ module PullRequest
30
+ # Handle a Github Pull Request event
31
+ def event_pull_request(config)
32
+ # Safely load the JSON event data
33
+ @payload = parse_request_body
34
+ Cyclid.logger.debug "hook payload=#{@payload.inspect}"
35
+
36
+ # Do we know what to do with this action?
37
+ action = @payload['action'] || nil
38
+
39
+ Cyclid.logger.debug "action=#{action}"
40
+ return true unless action == 'opened' \
41
+ or action == 'reopened' \
42
+ or action == 'synchronize'
43
+
44
+ # Get the list of files in the root of the repository in the
45
+ # Pull Request branch
46
+ clone_url = URI(pr_clone_url)
47
+
48
+ # Get the authentication key
49
+ auth_token = find_oauth_token(config, clone_url)
50
+
51
+ return_failure(400, "can not find a valid OAuth token for #{clone_url}") \
52
+ if auth_token.nil?
53
+
54
+ # Create an Octokit client
55
+ @client = Octokit::Client.new(access_token: auth_token)
56
+
57
+ # Set the PR to 'pending'
58
+ @client.create_status(pr_repository, pr_sha, 'pending',
59
+ context: 'Cyclid', description: 'Preparing build')
60
+
61
+ # Get the Pull Request
62
+ tree = @client.tree(pr_repository, pr_sha, recursive: false)
63
+ Cyclid.logger.debug "tree=#{tree.to_hash}"
64
+
65
+ # Find the Cyclid job file (if it exists)
66
+ job_sha, job_type = find_job_file(tree)
67
+ Cyclid.logger.debug "job_sha=#{job_sha}"
68
+
69
+ if job_sha.nil?
70
+ @client.create_status(pr_repository, pr_sha, 'error',
71
+ context: 'Cyclid', description: 'No Cyclid job file found')
72
+
73
+ return_failure(400, 'not a Cyclid repository')
74
+ end
75
+
76
+ # Get the job file
77
+ begin
78
+ job_definition = load_job_file(pr_repository, job_sha, job_type)
79
+
80
+ # Insert this repository & branch into the sources
81
+ #
82
+ # XXX Could this cause collisions between the existing sources in
83
+ # the job definition? Not entirely sure what the workflow will
84
+ # look like.
85
+ job_sources = job_definition['sources'] || []
86
+ job_sources << { 'type' => 'git',
87
+ 'url' => clone_url.to_s,
88
+ 'branch' => pr_ref,
89
+ 'token' => auth_token }
90
+ job_definition['sources'] = job_sources
91
+
92
+ Cyclid.logger.debug "sources=#{job_definition['sources']}"
93
+ rescue StandardError => ex
94
+ Cyclid.logger.error "failed to retrieve Github Pull Request job: #{ex}"
95
+
96
+ @client.create_status(pr_repository, pr_sha, 'error',
97
+ context: 'Cyclid',
98
+ description: "Couldn't retrieve Cyclid job file")
99
+ return_failure(400, 'not a Cyclid repository')
100
+ end
101
+
102
+ Cyclid.logger.debug "job_definition=#{job_definition}"
103
+
104
+ begin
105
+ # Retrieve the plugin configuration
106
+ plugins_config = Cyclid.config.plugins
107
+ github_config = load_github_config(plugins_config)
108
+
109
+ ui_url = github_config[:ui_url]
110
+ linkback_url = "#{ui_url}/#{organization_name}"
111
+
112
+ # Inject some useful context data
113
+ ctx = { gh_event: 'pull_request',
114
+ gh_user: pull_request['user']['login'],
115
+ gh_ref: pr_ref,
116
+ gh_comment: pull_request['body'] }
117
+
118
+ callback = GithubCallback.new(auth_token, pr_repository, pr_sha, linkback_url)
119
+ job_from_definition(job_definition, callback, ctx)
120
+ rescue StandardError
121
+ @client.create_status(pr_repository, pr_sha, 'error',
122
+ context: 'Cyclid', description: 'An unknown error occurred')
123
+
124
+ return_failure(500, 'job failed')
125
+ end
126
+
127
+ return true
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,121 @@
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 'octokit'
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
+ # Github plugin method callbacks
27
+ module GithubMethods
28
+ # Handle a Pull Request event
29
+ module Push
30
+ # Handle a Github Push event
31
+ def event_push(config)
32
+ # Safely load the JSON event data
33
+ @payload = parse_request_body
34
+ Cyclid.logger.debug "hook payload=#{@payload.inspect}"
35
+
36
+ # Get the list of files in the root of the repository in the
37
+ # push branch
38
+ clone_url = URI(push_clone_url)
39
+
40
+ # Get the authentication key
41
+ auth_token = find_oauth_token(config, clone_url)
42
+
43
+ return_failure(400, "can not find a valid OAuth token for #{clone_url}") \
44
+ if auth_token.nil?
45
+
46
+ # Create an Octokit client
47
+ @client = Octokit::Client.new(access_token: auth_token)
48
+
49
+ # Get the push head
50
+ tree = @client.tree(push_repository, push_sha, recursive: false)
51
+ Cyclid.logger.debug "tree=#{tree.to_hash}"
52
+
53
+ # Find the Cyclid job file (if it exists)
54
+ job_sha, job_type = find_job_file(tree)
55
+ Cyclid.logger.debug "job_sha=#{job_sha}"
56
+
57
+ if job_sha.nil?
58
+ @client.create_status(push_repository, push_sha, 'error',
59
+ context: 'Cyclid', description: 'No Cyclid job file found')
60
+ return_failure(400, 'not a Cyclid repository')
61
+ end
62
+
63
+ # Get the job file
64
+ begin
65
+ job_definition = load_job_file(push_repository, job_sha, job_type)
66
+
67
+ # Insert this repository & branch into the sources
68
+ #
69
+ # XXX Could this cause collisions between the existing sources in
70
+ # the job definition? Not entirely sure what the workflow will
71
+ # look like.
72
+ job_sources = job_definition['sources'] || []
73
+ job_sources << { 'type' => 'git',
74
+ 'url' => clone_url.to_s,
75
+ 'branch' => push_ref,
76
+ 'token' => auth_token }
77
+ job_definition['sources'] = job_sources
78
+
79
+ Cyclid.logger.debug "sources=#{job_definition['sources']}"
80
+ rescue StandardError => ex
81
+ Cyclid.logger.error "failed to retrieve Github Push job: #{ex}"
82
+
83
+ @client.create_status(push_repository, push_sha, 'error',
84
+ context: 'Cyclid',
85
+ description: "Couldn't retrieve Cyclid job file")
86
+ return_failure(400, 'not a Cyclid repository')
87
+ end
88
+
89
+ Cyclid.logger.debug "job_definition=#{job_definition}"
90
+
91
+ begin
92
+ # Retrieve the plugin configuration
93
+ plugins_config = Cyclid.config.plugins
94
+ github_config = load_github_config(plugins_config)
95
+
96
+ ui_url = github_config[:ui_url]
97
+ linkback_url = "#{ui_url}/#{organization_name}"
98
+
99
+ # Inject some useful context data
100
+ ctx = { gh_event: 'push',
101
+ gh_user: @payload['sender']['login'],
102
+ gh_ref: push_ref,
103
+ gh_comment: push_head_commit['message'] }
104
+
105
+ callback = GithubCallback.new(auth_token, push_repository, push_sha, linkback_url)
106
+ job_from_definition(job_definition, callback, ctx)
107
+ rescue StandardError
108
+ @client.create_status(push_repository, push_sha, 'error',
109
+ context: 'Cyclid', description: 'An unknown error occurred')
110
+
111
+ return_failure(500, 'job failed')
112
+ end
113
+
114
+ return true
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -103,7 +103,7 @@ module Cyclid
103
103
  @job_record.save!
104
104
 
105
105
  # Ping the callback status_changed hook, if required
106
- @callback.status_changed(@job_id, status) if @callback
106
+ @callback&.status_changed(@job_id, status)
107
107
  end
108
108
 
109
109
  # Set the JobRecord ended
@@ -114,7 +114,7 @@ module Cyclid
114
114
 
115
115
  # Ping the callback completion hook, if required
116
116
  def completion(success)
117
- @callback.completion(@job_id, success) if @callback
117
+ @callback&.completion(@job_id, success)
118
118
  end
119
119
 
120
120
  # Write data to the log buffer
@@ -122,7 +122,7 @@ module Cyclid
122
122
  @log_buffer.write data
123
123
 
124
124
  # Ping the callback log_write hook, if required
125
- @callback.log_write(@job_id, data) if @callback
125
+ @callback&.log_write(@job_id, data)
126
126
  end
127
127
  end
128
128
  end
@@ -43,11 +43,12 @@ module Cyclid
43
43
  raise 'failed to update repositories' unless success
44
44
  end
45
45
 
46
- env[:packages].each do |package|
46
+ if env.key? :packages
47
47
  success = transport.exec \
48
- "sudo -E apt-get install -y #{package}"
49
- raise "failed to install package #{package}" unless success
50
- end if env.key? :packages
48
+ "sudo -E apt-get install -y #{env[:packages].join(' ')}" \
49
+
50
+ raise "failed to install packages #{env[:packages].join(' ')}" unless success
51
+ end
51
52
  rescue StandardError => ex
52
53
  Cyclid.logger.error "failed to provision #{buildhost[:name]}: #{ex}"
53
54
  raise
@@ -68,18 +69,18 @@ module Cyclid
68
69
  "echo '#{fragment}' | sudo tee -a /etc/apt/sources.list.d/cyclid.list"
69
70
  raise "failed to add repository #{url}" unless success
70
71
 
71
- if repo.key? :key_id
72
- # Import the signing key
73
- key_id = repo[:key_id]
72
+ return unless repo.key? :key_id
74
73
 
75
- success = transport.exec \
76
- "gpg --keyserver keyserver.ubuntu.com --recv-keys #{key_id}"
77
- raise "failed to import key #{key_id}" unless success
74
+ # Import the signing key
75
+ key_id = repo[:key_id]
78
76
 
79
- success = transport.exec \
80
- "gpg -a --export #{key_id} | sudo apt-key add -"
81
- raise "failed to add repository key #{key_id}" unless success
82
- end
77
+ success = transport.exec \
78
+ "gpg --keyserver keyserver.ubuntu.com --recv-keys #{key_id}"
79
+ raise "failed to import key #{key_id}" unless success
80
+
81
+ success = transport.exec \
82
+ "gpg -a --export #{key_id} | sudo apt-key add -"
83
+ raise "failed to add repository key #{key_id}" unless success
83
84
  end
84
85
 
85
86
  # Register this plugin
@@ -46,11 +46,12 @@ module Cyclid
46
46
  raise 'failed to update repositories' unless success
47
47
  end
48
48
 
49
- env[:packages].each do |package|
49
+ if env.key? :packages
50
50
  success = transport.exec \
51
- "sudo -E apt-get install -y #{package}"
52
- raise "failed to install package #{package}" unless success
53
- end if env.key? :packages
51
+ "sudo -E apt-get install -y #{env[:packages].join(' ')}" \
52
+
53
+ raise "failed to install packages #{env[:packages].join(' ')}" unless success
54
+ end
54
55
  rescue StandardError => ex
55
56
  Cyclid.logger.error "failed to provision #{buildhost[:name]}: #{ex}"
56
57
  raise
@@ -76,18 +77,18 @@ module Cyclid
76
77
  "echo '#{fragment}' | sudo tee -a /etc/apt/sources.list.d/cyclid.list"
77
78
  raise "failed to add repository #{url}" unless success
78
79
 
79
- if repo.key? :key_id
80
- # Import the signing key
81
- key_id = repo[:key_id]
80
+ return unless repo.key? :key_id
82
81
 
83
- success = transport.exec \
84
- "gpg --keyserver keyserver.ubuntu.com --recv-keys #{key_id}"
85
- raise "failed to import key #{key_id}" unless success
82
+ # Import the signing key
83
+ key_id = repo[:key_id]
86
84
 
87
- success = transport.exec \
88
- "gpg -a --export #{key_id} | sudo apt-key add -"
89
- raise "failed to add repository key #{key_id}" unless success
90
- end
85
+ success = transport.exec \
86
+ "gpg --keyserver keyserver.ubuntu.com --recv-keys #{key_id}"
87
+ raise "failed to import key #{key_id}" unless success
88
+
89
+ success = transport.exec \
90
+ "gpg -a --export #{key_id} | sudo apt-key add -"
91
+ raise "failed to add repository key #{key_id}" unless success
91
92
  end
92
93
 
93
94
  # Register this plugin
@@ -48,7 +48,7 @@ module Cyclid
48
48
 
49
49
  branch = source[:branch]
50
50
 
51
- match = url.path.match(%r{^.*\/(\w*)})
51
+ match = url.path.match(%r{^.*\/([^\.]*)})
52
52
  source_dir = "#{ctx[:workspace]}/#{match[1]}"
53
53
 
54
54
  success = transport.exec("git fetch origin #{branch}:#{branch}", source_dir)
@@ -52,8 +52,10 @@ module Cyclid
52
52
  keys: keys,
53
53
  timeout: 5)
54
54
  break unless @session.nil?
55
- rescue Net::SSH::AuthenticationFailed
55
+ rescue Net::SSH::Exception
56
56
  Cyclid.logger.debug 'SSH authentication failed'
57
+ rescue StandardError => ex
58
+ Cyclid.logger.debug "SSH connection failed: #{ex}"
57
59
  end
58
60
 
59
61
  sleep 5
@@ -22,6 +22,12 @@ module Cyclid
22
22
  module API
23
23
  # Sinatra helpers
24
24
  module APIHelpers
25
+ # Return the raw request body
26
+ def request_body
27
+ request.body.rewind
28
+ request.body.read
29
+ end
30
+
25
31
  # Safely parse & validate the request body
26
32
  def parse_request_body
27
33
  # Parse the the request
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Cyclid
3
3
  module Api
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.2'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cyclid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristian Van Der Vliet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-05 00:00:00.000000000 Z
11
+ date: 2016-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -276,6 +276,20 @@ dependencies:
276
276
  - - "~>"
277
277
  - !ruby/object:Gem::Version
278
278
  version: '1.5'
279
+ - !ruby/object:Gem::Dependency
280
+ name: octokit
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - "~>"
284
+ - !ruby/object:Gem::Version
285
+ version: '4.3'
286
+ type: :runtime
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - "~>"
291
+ - !ruby/object:Gem::Version
292
+ version: '4.3'
279
293
  - !ruby/object:Gem::Dependency
280
294
  name: cyclid-core
281
295
  requirement: !ruby/object:Gem::Requirement
@@ -357,9 +371,14 @@ files:
357
371
  - app/cyclid/plugins/action/slack/note.erb
358
372
  - app/cyclid/plugins/api.rb
359
373
  - app/cyclid/plugins/api/github.rb
374
+ - app/cyclid/plugins/api/github/README.md
360
375
  - app/cyclid/plugins/api/github/callback.rb
376
+ - app/cyclid/plugins/api/github/config.rb
377
+ - app/cyclid/plugins/api/github/helpers.rb
361
378
  - app/cyclid/plugins/api/github/methods.rb
362
- - app/cyclid/plugins/api/github/status.rb
379
+ - app/cyclid/plugins/api/github/oauth.rb
380
+ - app/cyclid/plugins/api/github/pull_request.rb
381
+ - app/cyclid/plugins/api/github/push.rb
363
382
  - app/cyclid/plugins/builder.rb
364
383
  - app/cyclid/plugins/builder/mist.rb
365
384
  - app/cyclid/plugins/dispatcher.rb