autoproj-jenkins 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +11 -0
- data/autoproj-jenkins.gemspec +28 -0
- data/lib/autoproj/cli/jenkins.rb +100 -0
- data/lib/autoproj/cli/main_jenkins.rb +123 -0
- data/lib/autoproj/cli/test_postprocessing.rb +85 -0
- data/lib/autoproj/jenkins/credentials.rb +67 -0
- data/lib/autoproj/jenkins/exceptions.rb +7 -0
- data/lib/autoproj/jenkins/relativize.rb +74 -0
- data/lib/autoproj/jenkins/render_template.rb +92 -0
- data/lib/autoproj/jenkins/server.rb +79 -0
- data/lib/autoproj/jenkins/templates/abort-if-upstream-failed.pipeline.erb +18 -0
- data/lib/autoproj/jenkins/templates/bootstrap.pipeline.erb +27 -0
- data/lib/autoproj/jenkins/templates/buildconf-Gemfile +3 -0
- data/lib/autoproj/jenkins/templates/buildconf-config.yml.erb +12 -0
- data/lib/autoproj/jenkins/templates/buildconf-vagrant-Gemfile +4 -0
- data/lib/autoproj/jenkins/templates/buildconf.pipeline.erb +43 -0
- data/lib/autoproj/jenkins/templates/buildconf.xml.erb +24 -0
- data/lib/autoproj/jenkins/templates/handle-downstream.pipeline.erb +20 -0
- data/lib/autoproj/jenkins/templates/import-archive.pipeline.erb +2 -0
- data/lib/autoproj/jenkins/templates/import-git.pipeline.erb +16 -0
- data/lib/autoproj/jenkins/templates/import-svn.pipeline.erb +13 -0
- data/lib/autoproj/jenkins/templates/jenkins_dependency_overrides.rb.erb +5 -0
- data/lib/autoproj/jenkins/templates/package-Gemfile +2 -0
- data/lib/autoproj/jenkins/templates/package.pipeline.erb +102 -0
- data/lib/autoproj/jenkins/templates/package.xml.erb +23 -0
- data/lib/autoproj/jenkins/templates/setup-git-credentials.pipeline.erb +8 -0
- data/lib/autoproj/jenkins/templates/wait-upstream.pipeline.erb +160 -0
- data/lib/autoproj/jenkins/test_format_converters/boost-test.xsl +347 -0
- data/lib/autoproj/jenkins/updater.rb +214 -0
- data/lib/autoproj/jenkins/version.rb +5 -0
- data/lib/autoproj/jenkins.rb +19 -0
- data/lib/autoproj-jenkins.rb +8 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f5d96120cc78350275e92584c61af35c413bcafb
|
4
|
+
data.tar.gz: d1bd6d3060ea76972df27145c9fceed592354ba9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d3f538eac2dd5471fb6bcf43f5f788e7babbe67ce8ced5edc8cc73a10eefeeece7e57dc9c55eacf37c2ebbac9b38ee27b2eec1e8112a78ef14fd28ad883e80d
|
7
|
+
data.tar.gz: 31525d9641c6df34e2b1b41af1700d3436381ca40bdacb3a4ec1b8b145598babbee284c4def436bb58d686ef721c3e89cf2f7d11da01be6e5682642846bd5e3e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Sylvain Joyeux
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Autoproj::Jenkins
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/autoproj/jenkins`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'autoproj-jenkins'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install autoproj-jenkins
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/autoproj-jenkins.
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
41
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'autoproj/jenkins/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "autoproj-jenkins"
|
8
|
+
spec.version = Autoproj::Jenkins::VERSION
|
9
|
+
spec.authors = ["Sylvain Joyeux"]
|
10
|
+
spec.email = ["sylvain.joyeux@m4x.org"]
|
11
|
+
|
12
|
+
spec.summary = %q{Exporting an autoproj build to a jenkins server}
|
13
|
+
spec.homepage = "https://github.com/doudou/autoproj-jenkins"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'jenkins_api_client'
|
22
|
+
spec.add_dependency 'autoproj', '>= 2.0.0.rc20'
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
24
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
spec.add_development_dependency "simplecov"
|
27
|
+
spec.add_development_dependency "flexmock"
|
28
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'autoproj/cli/inspection_tool'
|
2
|
+
require 'autoproj/jenkins'
|
3
|
+
|
4
|
+
module Autoproj
|
5
|
+
module CLI
|
6
|
+
class Jenkins < Autoproj::CLI::InspectionTool
|
7
|
+
attr_reader :server
|
8
|
+
attr_reader :updater
|
9
|
+
|
10
|
+
def initialize(ws, job_prefix: '', **options)
|
11
|
+
super(ws)
|
12
|
+
@server = Autoproj::Jenkins::Server.new(**options)
|
13
|
+
@updater = Autoproj::Jenkins::Updater.new(ws, server, job_prefix: job_prefix)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_vcs_credentials(credentials)
|
17
|
+
results = Autoproj::Jenkins::Credentials.new
|
18
|
+
credentials.each do |argument|
|
19
|
+
credential = Autoproj::Jenkins::Credentials.parse(argument)
|
20
|
+
results.add(credential)
|
21
|
+
end
|
22
|
+
results
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_or_update_buildconf_job(*package_names, force: false, dev: false, credentials_id: nil, vcs_credentials: [])
|
26
|
+
initialize_and_load
|
27
|
+
|
28
|
+
if dev
|
29
|
+
gemfile = 'buildconf-vagrant-Gemfile'
|
30
|
+
autoproj_install_path = '/opt/autoproj/bin/autoproj_install'
|
31
|
+
else
|
32
|
+
gemfile = 'buildconf-Gemfile'
|
33
|
+
autoproj_install_path = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
finalize_setup(package_names, recursive: false, non_imported_packages: :return)
|
37
|
+
updater.create_or_update_buildconf_job(*package_names, gemfile: gemfile,
|
38
|
+
autoproj_install_path: autoproj_install_path, dev: dev,
|
39
|
+
credentials_id: credentials_id,
|
40
|
+
vcs_credentials: parse_vcs_credentials(vcs_credentials))
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_or_update_packages(*package_names, dev: false, vcs_credentials: [])
|
44
|
+
initialize_and_load
|
45
|
+
source_packages, _ = finalize_setup(package_names, non_imported_packages: nil)
|
46
|
+
source_packages = source_packages.map do |package_name|
|
47
|
+
ws.manifest.package_definition_by_name(package_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
if dev
|
51
|
+
gemfile = 'buildconf-vagrant-Gemfile'
|
52
|
+
autoproj_install_path = '/opt/autoproj/bin/autoproj_install'
|
53
|
+
else
|
54
|
+
gemfile = 'buildconf-Gemfile'
|
55
|
+
autoproj_install_path = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
updater.update(
|
59
|
+
*source_packages,
|
60
|
+
gemfile: gemfile,
|
61
|
+
autoproj_install_path: autoproj_install_path,
|
62
|
+
vcs_credentials: parse_vcs_credentials(vcs_credentials))
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the "roots" in the trigger graph
|
66
|
+
#
|
67
|
+
# The trigger graph is the inverse of the dependency graph
|
68
|
+
# (a package's dependencies are built before the package itself)
|
69
|
+
#
|
70
|
+
# @param [Array<String>] package_names the packages whose trigger
|
71
|
+
# roots we want to find
|
72
|
+
# @return [Array<String>] the trigger root packages
|
73
|
+
def trigger_root_packages(*package_names)
|
74
|
+
package_names.find_all do |pkg_name|
|
75
|
+
pkg = ws.manifest.find_autobuild_package(pkg_name)
|
76
|
+
if !pkg
|
77
|
+
raise ArgumentError, "#{pkg_name} is not a known package"
|
78
|
+
end
|
79
|
+
pkg.dependencies.all? do |dep_name|
|
80
|
+
!package_names.include?(dep_name)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Trigger the build of the given packages
|
86
|
+
#
|
87
|
+
# It actually only triggers the jobs that are roots in the trigger
|
88
|
+
# graph
|
89
|
+
#
|
90
|
+
# @param [Array<String>] package_names the names of the packages to
|
91
|
+
# build
|
92
|
+
def trigger_packages(*package_names)
|
93
|
+
trigger_root_packages(*package_names).each do |pkg_name|
|
94
|
+
server.trigger_job(updater.job_name_from_package_name(pkg_name))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Autoproj
|
2
|
+
module CLI
|
3
|
+
# The 'jenkins' subcommand for autoproj
|
4
|
+
class MainJenkins < Thor
|
5
|
+
class_option :username, desc: 'username to the Jenkins CLI (a password will be requested if --password is not given)'
|
6
|
+
class_option :password, desc: 'password to the Jenkins CLI (needs --username)'
|
7
|
+
class_option :job_prefix, desc: 'string that should be used as prefix to all generated job names',
|
8
|
+
type: :string, default: ''
|
9
|
+
|
10
|
+
namespace 'jenkins'
|
11
|
+
|
12
|
+
no_commands do
|
13
|
+
def request_password
|
14
|
+
STDOUT.print "Password: "
|
15
|
+
STDOUT.flush
|
16
|
+
STDIN.noecho do |io|
|
17
|
+
io.readline.chomp
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_ops(url, target_os: nil)
|
22
|
+
if username = options[:username]
|
23
|
+
password = options[:password] || request_password
|
24
|
+
auth = Hash[username: username,
|
25
|
+
password: password]
|
26
|
+
elsif options[:password]
|
27
|
+
raise ArgumentError, "--password given without --username"
|
28
|
+
else
|
29
|
+
auth = Hash.new
|
30
|
+
end
|
31
|
+
|
32
|
+
workspace_options = Hash.new
|
33
|
+
if target_os
|
34
|
+
names, versions = target_os.split(':')
|
35
|
+
names = names.split(',')
|
36
|
+
names << 'default'
|
37
|
+
versions = versions.split(',')
|
38
|
+
versions << 'default'
|
39
|
+
workspace_options[:os_package_resolver] = OSPackageResolver.new(operating_system: [names, versions])
|
40
|
+
end
|
41
|
+
ws = Autoproj::Workspace.default(**workspace_options)
|
42
|
+
|
43
|
+
STDERR.puts "connecting to jenkins '#{url}' with prefix '#{options[:prefix]}'"
|
44
|
+
Jenkins.new(ws,
|
45
|
+
job_prefix: options[:job_prefix],
|
46
|
+
server_url: url,
|
47
|
+
**auth)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'init URL [PACKAGE NAMES]', 'initialize the jenkins server by creating the base build job, optionally restricting the build to certain packages'
|
52
|
+
option :force, desc: 'if set, delete any existing job'
|
53
|
+
option :trigger, desc: 'trigger the job once created',
|
54
|
+
type: :boolean, default: false
|
55
|
+
option :dev, desc: 'assume that the jenkins instance is a development instance under vagrant and that autoproj-jenkins is made available as /opt/autoproj-jenkins',
|
56
|
+
type: :boolean, default: false
|
57
|
+
option :target_os, desc: "the autoproj definition for the target OS as name0,name1:version0,version1",
|
58
|
+
default: nil
|
59
|
+
option :credentials_id, desc: "the credentials ID of the username/password credentials that autoproj-jenkins should use to access the jenkins CLI",
|
60
|
+
default: 'autoproj-jenkins-cli'
|
61
|
+
option :vcs_credentials, desc: 'list of vcs_type:URLs for which credentials should be provided (see documentation)',
|
62
|
+
type: :array, default: []
|
63
|
+
def init(url, *package_names)
|
64
|
+
require 'autoproj/cli/jenkins'
|
65
|
+
ops = create_ops(url, target_os: options[:target_os])
|
66
|
+
|
67
|
+
ops.create_or_update_buildconf_job(
|
68
|
+
*package_names,
|
69
|
+
credentials_id: options[:credentials_id],
|
70
|
+
force: options[:force],
|
71
|
+
vcs_credentials: options[:vcs_credentials],
|
72
|
+
dev: options[:dev])
|
73
|
+
if options[:trigger]
|
74
|
+
ops.trigger_buildconf_job
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
desc 'update [PACKAGE_NAMES]', 'add the following package and its dependencies to the jenkins build'
|
80
|
+
option :force, desc: 'ignore the current state, generate jobs as if nothing was ever done'
|
81
|
+
option :dev, desc: 'assume that the jenkins instance is a development instance under vagrant and that autoproj-jenkins is made available as /opt/autoproj-jenkins',
|
82
|
+
type: :boolean, default: false
|
83
|
+
option :vcs_credentials, desc: 'list of vcs_type:URLs for which credentials should be provided (see documentation)',
|
84
|
+
type: :array, default: []
|
85
|
+
def update(url, *package_names)
|
86
|
+
require 'autoproj/cli/jenkins'
|
87
|
+
ops = create_ops(url)
|
88
|
+
Autoproj.report(silent: !options[:debug], debug: options[:debug]) do
|
89
|
+
updated_jobs = ops.add_or_update_packages(*package_names, dev: options[:dev], vcs_credentials: options[:vcs_credentials])
|
90
|
+
updated_jobs.sort.each do |job_name|
|
91
|
+
puts job_name
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
desc 'postprocess-tests OUTPUT_DIR [PACKAGE_NAME]', 'postprocesses test result formatted in various formats to convert them into the JUnit XML format understood by Jenkins',
|
97
|
+
hide: true
|
98
|
+
option :after, desc: "if provided, any report file that is older than this file will be ignored",
|
99
|
+
default: nil
|
100
|
+
def postprocess_tests(output_dir, *package_names)
|
101
|
+
require 'autoproj/cli/test_postprocessing'
|
102
|
+
ops = TestPostprocessing.new(Workspace.default)
|
103
|
+
if options[:after]
|
104
|
+
reference_time = File.stat(options[:after]).mtime
|
105
|
+
end
|
106
|
+
ops.process(output_dir, *package_names, after: reference_time)
|
107
|
+
end
|
108
|
+
|
109
|
+
desc 'relativize ROOT_DIR INPUT_TEXT OUTPUT_TEXT', 'replaces INPUT_TEXT by OUTPUT_TEXT in all files that can contain absolute paths',
|
110
|
+
hide: true
|
111
|
+
def relativize(root_dir, input_text, output_text)
|
112
|
+
require 'autoproj/jenkins'
|
113
|
+
relativize = Autoproj::Jenkins::Relativize.new(Pathname.new(root_dir), input_text, output_text)
|
114
|
+
processed_paths = relativize.process
|
115
|
+
puts "modified #{processed_paths.size} file"
|
116
|
+
processed_paths.each do |p|
|
117
|
+
puts " #{p}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'autoproj/cli/inspection_tool'
|
2
|
+
|
3
|
+
module Autoproj
|
4
|
+
module CLI
|
5
|
+
class TestPostprocessing < Autoproj::CLI::InspectionTool
|
6
|
+
attr_reader :convertions
|
7
|
+
|
8
|
+
def self.test_format_converter_dir
|
9
|
+
File.expand_path(
|
10
|
+
File.join('..', 'jenkins', 'test_format_converters'),
|
11
|
+
__dir__)
|
12
|
+
end
|
13
|
+
|
14
|
+
TEST_RESULT_CONVERTERS = Hash[
|
15
|
+
'*.boost.xml' => File.join(test_format_converter_dir, 'boost-test.xsl'),
|
16
|
+
'*.junit.xml' => nil
|
17
|
+
]
|
18
|
+
|
19
|
+
def initialize(ws, convertions: TEST_RESULT_CONVERTERS)
|
20
|
+
super(ws)
|
21
|
+
@convertions = convertions
|
22
|
+
end
|
23
|
+
|
24
|
+
class ConvertionFailed < RuntimeError; end
|
25
|
+
|
26
|
+
def process(output_dir, *package_names, after: nil)
|
27
|
+
initialize_and_load
|
28
|
+
source_packages, _ = finalize_setup(package_names, recursive: false)
|
29
|
+
source_packages = source_packages.map do |package_name|
|
30
|
+
ws.manifest.package_definition_by_name(package_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
has_failures = false
|
34
|
+
source_packages.each do |pkg|
|
35
|
+
utility = pkg.autobuild.test_utility
|
36
|
+
found_something = false
|
37
|
+
convertions.each do |glob, xsl|
|
38
|
+
Dir.glob(File.join(utility.target_dir, glob)) do |input_file|
|
39
|
+
input_mtime = File.stat(input_file).mtime
|
40
|
+
if after && input_mtime < after
|
41
|
+
Autoproj.message " ignoring #{input_file}, its modification time is #{input_mtime} which is after #{after}"
|
42
|
+
next
|
43
|
+
end
|
44
|
+
|
45
|
+
found_something = true
|
46
|
+
FileUtils.mkdir_p output_dir
|
47
|
+
output_file = File.join(output_dir, File.basename(input_file))
|
48
|
+
begin
|
49
|
+
if xsl
|
50
|
+
xsl_process(input_file, xsl, output_file)
|
51
|
+
else
|
52
|
+
FileUtils.copy_file input_file, output_file
|
53
|
+
end
|
54
|
+
Autoproj.message " generated #{output_file} from #{input_file} for #{pkg.name}"
|
55
|
+
rescue Exception => e
|
56
|
+
Autoproj.error e.message
|
57
|
+
has_failures = true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if !found_something
|
63
|
+
Autoproj.message "found no test results for #{pkg.name}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
ensure
|
67
|
+
if has_failures
|
68
|
+
raise ConvertionFailed, "some files failed to convert, see output for more details"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def xsl_process(input_file, stylesheet, output_file)
|
73
|
+
if File.read(input_file).strip.empty?
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
if !system('saxonb-xslt', "-o:#{output_file}", "-xsl:#{stylesheet}", "-s:#{input_file}")
|
78
|
+
raise ArgumentError, "failed to convert #{input_file} using #{stylesheet}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Autoproj::Jenkins
|
2
|
+
# Management of the mapping from a VCS description to the corresponding
|
3
|
+
# Jenkins credential
|
4
|
+
class Credentials
|
5
|
+
Credential = Struct.new :vcs, :protocol, :host do
|
6
|
+
# Whether this credential object matches the given VCS
|
7
|
+
#
|
8
|
+
# @param [Autoproj::VCSDefinition] vcs
|
9
|
+
def matches?(vcs)
|
10
|
+
return if vcs.type.to_sym != self.vcs
|
11
|
+
vcs_url = URI.parse(vcs.url)
|
12
|
+
vcs_url.scheme == protocol &&
|
13
|
+
vcs_url.host == host
|
14
|
+
end
|
15
|
+
|
16
|
+
# The ID of the jenkins credential
|
17
|
+
def jenkins_id
|
18
|
+
"autoproj-#{vcs}-#{protocol}-#{host}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Parse a string that represents a single credential and return it
|
23
|
+
#
|
24
|
+
# @param [String] string a string of the form "vcs_type:URI", e.g.
|
25
|
+
# "git:https://github.com"
|
26
|
+
# @return [Credential]
|
27
|
+
def self.parse(string)
|
28
|
+
vcs, *uri = string.split(':')
|
29
|
+
if !vcs || vcs.empty? || uri.empty?
|
30
|
+
raise ArgumentError, "expected VCS:URL but got #{string}"
|
31
|
+
elsif !Autoproj::Jenkins.vcs_supported?(vcs)
|
32
|
+
raise UnhandledVCS, "#{vcs} is not a supported VCS"
|
33
|
+
end
|
34
|
+
uri = URI.parse(uri.join(':'))
|
35
|
+
Credential.new(vcs.to_sym, uri.scheme, uri.host)
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :credentials
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@credentials = Hash.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def empty?
|
45
|
+
credentials.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](vcs)
|
49
|
+
credentials[vcs.to_sym] || Array.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def add(credential)
|
53
|
+
(credentials[credential.vcs] ||= Array.new) << credential
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return the credential description for the given VCS
|
57
|
+
#
|
58
|
+
# @param [Autoproj::VCSDefinition] vcs
|
59
|
+
# @return [nil,Credential]
|
60
|
+
def for(vcs)
|
61
|
+
self[vcs.type].find do |c|
|
62
|
+
c.matches?(vcs)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Autoproj
|
2
|
+
module Jenkins
|
3
|
+
# Process files that might contain full paths and transform them by
|
4
|
+
# replacing the original path with a new one
|
5
|
+
class Relativize
|
6
|
+
FILE_PATTERN = Regexp.union(
|
7
|
+
/\/pkgconfig\/.*.pc$/,
|
8
|
+
/\.cmake$/,
|
9
|
+
/\.txt$/
|
10
|
+
)
|
11
|
+
|
12
|
+
# The path of the root to be filtered
|
13
|
+
#
|
14
|
+
# @return [Pathname]
|
15
|
+
attr_reader :root_path
|
16
|
+
|
17
|
+
# The text to be replaced
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
attr_reader :original_text
|
21
|
+
|
22
|
+
# The text replacing {#original_text}
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
attr_reader :replacement_text
|
26
|
+
|
27
|
+
# A pattern used to filter which files should be filtered
|
28
|
+
#
|
29
|
+
# @return [#===]
|
30
|
+
attr_reader :file_pattern
|
31
|
+
|
32
|
+
def initialize(root_path, original_text, replacement_text, file_pattern: FILE_PATTERN)
|
33
|
+
@root_path = root_path
|
34
|
+
@original_text = original_text
|
35
|
+
@replacement_text = replacement_text
|
36
|
+
@file_pattern = file_pattern
|
37
|
+
end
|
38
|
+
|
39
|
+
# Process all files matching {#file_pattern} within {#root_path}
|
40
|
+
#
|
41
|
+
# @return [Array<Pathname>] the files that have been processed
|
42
|
+
def process
|
43
|
+
processed_files = Array.new
|
44
|
+
root_path.find do |candidate|
|
45
|
+
if candidate.file? && (file_pattern === candidate.to_s)
|
46
|
+
if process_file(candidate)
|
47
|
+
processed_files << candidate
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
processed_files
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
# Replaces text in a given file
|
57
|
+
#
|
58
|
+
# @return [Boolean] true if the pattern was found
|
59
|
+
def process_file(path)
|
60
|
+
replaced = false
|
61
|
+
filtered = path.each_line.map do |line|
|
62
|
+
line.gsub(original_text) { replaced = true; replacement_text }
|
63
|
+
end
|
64
|
+
if replaced
|
65
|
+
path.open('w') do |io|
|
66
|
+
io.puts filtered.join
|
67
|
+
end
|
68
|
+
true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|