vtasks 0.0.8
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/.gitignore +13 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +51 -0
- data/CODEOWNERS +2 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +14 -0
- data/LICENSE +201 -0
- data/README.md +196 -0
- data/Rakefile +40 -0
- data/bin/console +7 -0
- data/bin/setup +11 -0
- data/gems.rb +2 -0
- data/lib/vtasks/docker/image/build.rb +54 -0
- data/lib/vtasks/docker/image/push.rb +17 -0
- data/lib/vtasks/docker/image/tag.rb +17 -0
- data/lib/vtasks/docker/image.rb +83 -0
- data/lib/vtasks/docker.rb +124 -0
- data/lib/vtasks/lint.rb +65 -0
- data/lib/vtasks/puppet.rb +212 -0
- data/lib/vtasks/release.rb +101 -0
- data/lib/vtasks/travisci.rb +58 -0
- data/lib/vtasks/utils/docker_shared_context.rb +91 -0
- data/lib/vtasks/utils/git.rb +46 -0
- data/lib/vtasks/utils/output.rb +68 -0
- data/lib/vtasks/utils/semver.rb +31 -0
- data/lib/vtasks/utils/system.rb +11 -0
- data/lib/vtasks/version.rb +5 -0
- data/lib/vtasks.rb +5 -0
- data/locales/config.yaml +21 -0
- data/vtasks.gemspec +37 -0
- metadata +188 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module Vtasks
|
2
|
+
class Docker
|
3
|
+
class Image
|
4
|
+
# Docker Build class
|
5
|
+
class Build
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/git'
|
8
|
+
include Vtasks::Utils::Git
|
9
|
+
require 'vtasks/utils/output'
|
10
|
+
include Vtasks::Utils::Output
|
11
|
+
|
12
|
+
attr_reader :image, :path, :build_date, :build_tag
|
13
|
+
|
14
|
+
def initialize(image, path, args={})
|
15
|
+
@image ||= image
|
16
|
+
@path ||= path
|
17
|
+
@build_date ||= args.fetch(:build_date)
|
18
|
+
@build_tag ||= args.fetch(:build_tag)
|
19
|
+
|
20
|
+
@cmd = 'docker image build'
|
21
|
+
end
|
22
|
+
|
23
|
+
def without_arguments
|
24
|
+
info "Pulling #{image}" # to speed up the building process
|
25
|
+
system "docker pull #{image}" unless ENV['DOCKER_NO_CACHE']
|
26
|
+
|
27
|
+
info "Building #{image}:#{build_tag}"
|
28
|
+
system "#{@cmd} -t #{image}:#{build_tag} #{path}"
|
29
|
+
|
30
|
+
if $?.exitstatus != 0
|
31
|
+
error 'Build command failed!'
|
32
|
+
abort
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_arguments
|
37
|
+
build_args = {
|
38
|
+
'BUILD_DATE' => build_date,
|
39
|
+
'VERSION' => build_tag,
|
40
|
+
'VCS_URL' => git_url,
|
41
|
+
'VCS_REF' => git_commit
|
42
|
+
}
|
43
|
+
|
44
|
+
build_args.map do |key, value|
|
45
|
+
@cmd += " --build-arg #{key}=#{value}"
|
46
|
+
end
|
47
|
+
|
48
|
+
without_arguments
|
49
|
+
end
|
50
|
+
|
51
|
+
end # class Build
|
52
|
+
end # class Image
|
53
|
+
end # class Docker
|
54
|
+
end # module Vtasks
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vtasks
|
2
|
+
class Docker
|
3
|
+
class Image
|
4
|
+
# Docker Push class
|
5
|
+
class Push
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/output'
|
8
|
+
include Vtasks::Utils::Output
|
9
|
+
|
10
|
+
def initialize(image, tag)
|
11
|
+
info "Pushing #{image}:#{tag}"
|
12
|
+
system "docker image push #{image}:#{tag}"
|
13
|
+
end
|
14
|
+
end # class Push
|
15
|
+
end # class Image
|
16
|
+
end # class Docker
|
17
|
+
end # module Vtasks
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vtasks
|
2
|
+
class Docker
|
3
|
+
class Image
|
4
|
+
# Docker Tag module
|
5
|
+
class Tag
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/output'
|
8
|
+
include Vtasks::Utils::Output
|
9
|
+
|
10
|
+
def initialize(image, oldtag, newtag)
|
11
|
+
info "Tagging #{image}:#{newtag}"
|
12
|
+
system "docker image tag #{image}:#{oldtag} #{image}:#{newtag}"
|
13
|
+
end
|
14
|
+
end # class Tag
|
15
|
+
end # class Image
|
16
|
+
end # class Docker
|
17
|
+
end # module Vtasks
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Vtasks
|
2
|
+
class Docker
|
3
|
+
# Docker Image class
|
4
|
+
class Image
|
5
|
+
# Include utility modules
|
6
|
+
require 'vtasks/utils/git'
|
7
|
+
include Vtasks::Utils::Git
|
8
|
+
require 'vtasks/utils/semver'
|
9
|
+
include Vtasks::Utils::Semver
|
10
|
+
|
11
|
+
# Include utility classes
|
12
|
+
require 'vtasks/docker/image/build'
|
13
|
+
require 'vtasks/docker/image/push'
|
14
|
+
require 'vtasks/docker/image/tag'
|
15
|
+
|
16
|
+
attr_reader :image, :path, :has_build_args, :tags
|
17
|
+
|
18
|
+
def initialize(image, path, args = {})
|
19
|
+
@image ||= image
|
20
|
+
@path ||= path
|
21
|
+
@has_build_args ||= args.fetch(:has_build_args, false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def tags
|
25
|
+
major, minor, patch = [
|
26
|
+
semver[:major],
|
27
|
+
semver[:minor],
|
28
|
+
semver[:patch]
|
29
|
+
].freeze
|
30
|
+
@tags = [
|
31
|
+
"#{major}.#{minor}.#{patch}",
|
32
|
+
"#{major}.#{minor}",
|
33
|
+
"#{major}",
|
34
|
+
'latest'
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Compose build date
|
39
|
+
def build_date
|
40
|
+
@build_date ||= ::Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
41
|
+
end
|
42
|
+
|
43
|
+
# Compose build tag
|
44
|
+
def build_tag
|
45
|
+
@build_tag ||= gitver.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
# Build image
|
49
|
+
def build
|
50
|
+
args = {
|
51
|
+
build_date: build_date,
|
52
|
+
build_tag: build_tag
|
53
|
+
}
|
54
|
+
build = Vtasks::Docker::Image::Build.new(image, path, args)
|
55
|
+
if has_build_args
|
56
|
+
build.with_arguments
|
57
|
+
else
|
58
|
+
build.without_arguments
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Tag image
|
63
|
+
def tag
|
64
|
+
tags.each do |tag|
|
65
|
+
Vtasks::Docker::Image::Tag.new(image, build_tag, tag)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Build image with tags
|
70
|
+
def build_with_tags
|
71
|
+
build
|
72
|
+
tag
|
73
|
+
end
|
74
|
+
|
75
|
+
# Push image
|
76
|
+
def push
|
77
|
+
tags.each do |tag|
|
78
|
+
Vtasks::Docker::Image::Push.new(image, tag)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end # class Image
|
82
|
+
end # class Docker
|
83
|
+
end # module Vtasks
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Vtasks
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
# Docker tasks
|
5
|
+
class Docker < ::Rake::TaskLib
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/output'
|
8
|
+
include Vtasks::Utils::Output
|
9
|
+
require 'vtasks/utils/system'
|
10
|
+
include Vtasks::Utils::System
|
11
|
+
|
12
|
+
# Include utility classes
|
13
|
+
require 'vtasks/docker/image'
|
14
|
+
|
15
|
+
attr_reader :args, :repo
|
16
|
+
|
17
|
+
def initialize(args = {})
|
18
|
+
@args ||= args
|
19
|
+
@repo ||= args.fetch(:repo)
|
20
|
+
|
21
|
+
check_docker
|
22
|
+
define_tasks
|
23
|
+
end
|
24
|
+
|
25
|
+
def define_tasks
|
26
|
+
namespace :docker do
|
27
|
+
list_images
|
28
|
+
garbage_collect
|
29
|
+
tasks
|
30
|
+
|
31
|
+
dockerfiles.each do |dockerfile|
|
32
|
+
path = File.basename(dockerfile)
|
33
|
+
add_namespace("#{repo}/#{path}", path)
|
34
|
+
end # dockerfiles.each
|
35
|
+
end # namespace :docker
|
36
|
+
end # def define_tasks
|
37
|
+
|
38
|
+
# Image namespace
|
39
|
+
def add_namespace(image, path)
|
40
|
+
namespace path.to_sym do |_args|
|
41
|
+
require 'rspec/core/rake_task'
|
42
|
+
::RSpec::Core::RakeTask.new(:spec) do |task|
|
43
|
+
task.pattern = "#{path}/spec/*_spec.rb"
|
44
|
+
end
|
45
|
+
|
46
|
+
docker_image = Vtasks::Docker::Image.new(image, path, args)
|
47
|
+
|
48
|
+
lint_image(path)
|
49
|
+
|
50
|
+
desc 'Build and tag docker image'
|
51
|
+
task :build do
|
52
|
+
docker_image.build_with_tags
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'Publish docker image'
|
56
|
+
task :push do
|
57
|
+
docker_image.push
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Tasks
|
63
|
+
def tasks
|
64
|
+
# Run tasks one by one for all images
|
65
|
+
[:spec, :lint].each { |task_name| run_task(task_name) }
|
66
|
+
# Run tasks in parallel for all images
|
67
|
+
[:build, :push].each { |task_name| run_task_parallel(task_name) }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Run a task for all images
|
71
|
+
def run_task(name)
|
72
|
+
desc "Run #{name} for all images in repository"
|
73
|
+
task name => dockerfiles
|
74
|
+
.collect { |image| "docker:#{File.basename(image)}:#{name}" }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Run a task for all images in parallel
|
78
|
+
def run_task_parallel(name)
|
79
|
+
desc "Run #{name} for all images in repository in parallel"
|
80
|
+
multitask name => dockerfiles
|
81
|
+
.collect { |image| "docker:#{File.basename(image)}:#{name}" }
|
82
|
+
end
|
83
|
+
|
84
|
+
# List all folders containing Dockerfiles
|
85
|
+
def dockerfiles
|
86
|
+
@dockerfiles = Dir.glob('*').select do |dir|
|
87
|
+
File.directory?(dir) && File.exist?("#{dir}/Dockerfile")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Check Docker is installed
|
92
|
+
def check_docker
|
93
|
+
task :docker do
|
94
|
+
raise 'These tasks require docker to be installed' unless command? 'docker'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# List all images
|
99
|
+
def list_images
|
100
|
+
desc 'List all Docker images'
|
101
|
+
task :list do
|
102
|
+
info dockerfiles.map { |image| File.basename(image) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Lint image
|
107
|
+
def lint_image(path)
|
108
|
+
desc 'Run Hadolint against the Dockerfile'
|
109
|
+
task :lint do
|
110
|
+
dockerfile = "#{path}/Dockerfile"
|
111
|
+
info "Running Hadolint to check the style of #{dockerfile}"
|
112
|
+
system "docker container run --rm -i lukasmartinelli/hadolint hadolint --ignore DL3008 --ignore DL3013 - < #{dockerfile}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Garbage collect
|
117
|
+
def garbage_collect
|
118
|
+
desc 'Garbage collect unused docker data'
|
119
|
+
task :gc do
|
120
|
+
system 'docker system prune --all --force'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end # class Docker
|
124
|
+
end # module Vtasks
|
data/lib/vtasks/lint.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Vtasks
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
# Lint tasks
|
5
|
+
class Lint < ::Rake::TaskLib
|
6
|
+
attr_reader :file_list
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@file_list ||= options.fetch(:file_list, FileList['{lib,spec}/**/*.rb'])
|
10
|
+
define_tasks
|
11
|
+
end
|
12
|
+
|
13
|
+
# Define tasks
|
14
|
+
def define_tasks
|
15
|
+
desc 'Check for code smells with Reek and Rubocop'
|
16
|
+
task lint: ['lint:reek', 'lint:rubocop']
|
17
|
+
|
18
|
+
namespace :lint do
|
19
|
+
rubocop
|
20
|
+
reek
|
21
|
+
rubycritic
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# RuboCop
|
26
|
+
def rubocop
|
27
|
+
begin
|
28
|
+
require 'rubocop/rake_task'
|
29
|
+
rescue LoadError
|
30
|
+
nil # Might be in a group that is not installed
|
31
|
+
end
|
32
|
+
desc 'Run RuboCop on the tasks and lib directory'
|
33
|
+
::RuboCop::RakeTask.new(:rubocop) do |task|
|
34
|
+
task.patterns = file_list
|
35
|
+
task.options = ['--display-cop-names', '--extra-details']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Reek
|
40
|
+
def reek
|
41
|
+
begin
|
42
|
+
require 'reek/rake/task'
|
43
|
+
rescue LoadError
|
44
|
+
nil # Might be in a group that is not installed
|
45
|
+
end
|
46
|
+
::Reek::Rake::Task.new do |task|
|
47
|
+
task.source_files = file_list
|
48
|
+
task.fail_on_error = false
|
49
|
+
task.reek_opts = '--wiki-links --color'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Ruby Critic
|
54
|
+
def rubycritic
|
55
|
+
begin
|
56
|
+
require 'rubycritic/rake_task'
|
57
|
+
rescue LoadError
|
58
|
+
nil # Might be in a group that is not installed
|
59
|
+
end
|
60
|
+
::RubyCritic::RakeTask.new do |task|
|
61
|
+
task.paths = file_list
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end # class Lint
|
65
|
+
end # module Vtasks
|
@@ -0,0 +1,212 @@
|
|
1
|
+
module Vtasks
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
# Puppet tasks
|
5
|
+
class Puppet < ::Rake::TaskLib
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/git'
|
8
|
+
include Vtasks::Utils::Git
|
9
|
+
require 'vtasks/utils/output'
|
10
|
+
include Vtasks::Utils::Output
|
11
|
+
|
12
|
+
require 'json'
|
13
|
+
require 'open-uri'
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
attr_reader :exclude_paths
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
# Fix for namespaced :syntax task
|
20
|
+
task syntax: ['puppet:syntax']
|
21
|
+
|
22
|
+
namespace :puppet do
|
23
|
+
begin
|
24
|
+
require 'r10k/cli'
|
25
|
+
require 'r10k/puppetfile'
|
26
|
+
require 'puppet_forge'
|
27
|
+
require 'puppetlabs_spec_helper/rake_tasks' # ORDER IS VERY IMPORTANT BECAUSE IT OVERRIDES A LOT OF OTHER TASKS; AS OF NOW IT NEEDS TO BE AFTER `r10k` and `puppet_forge` (BECAUSE OF FAST_GETTEXT INITIALIZATION) BUT BEFORE puppet-strings (BECAUSE ERROR: `Don't know how to build task 'spec_prep'`)
|
28
|
+
require 'metadata-json-lint/rake_task'
|
29
|
+
require 'puppet-syntax/tasks/puppet-syntax'
|
30
|
+
require 'puppet-lint/tasks/puppet-lint'
|
31
|
+
require 'puppet-strings/tasks'
|
32
|
+
require 'puppet_blacksmith/rake_tasks'
|
33
|
+
rescue LoadError
|
34
|
+
nil # Might be in a group that is not installed
|
35
|
+
end
|
36
|
+
|
37
|
+
@exclude_paths ||= options.fetch(
|
38
|
+
:exclude_paths,
|
39
|
+
[
|
40
|
+
'bundle/**/*',
|
41
|
+
'modules/**/*',
|
42
|
+
'pkg/**/*',
|
43
|
+
'spec/**/*',
|
44
|
+
'tmp/**/*',
|
45
|
+
'vendor/**/*'
|
46
|
+
]
|
47
|
+
)
|
48
|
+
|
49
|
+
define_tasks
|
50
|
+
end # namespace :puppet
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_tasks
|
54
|
+
::PuppetLint::RakeTask.new :lint do |config|
|
55
|
+
config.relative = true
|
56
|
+
config.with_context = true
|
57
|
+
config.fail_on_warnings = true
|
58
|
+
config.ignore_paths = exclude_paths
|
59
|
+
config.disable_checks = [
|
60
|
+
'140chars'
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Puppet syntax tasks
|
65
|
+
::PuppetSyntax.exclude_paths = exclude_paths
|
66
|
+
|
67
|
+
desc 'Run syntax, lint, and spec tests'
|
68
|
+
task test: [
|
69
|
+
:metadata_lint,
|
70
|
+
:syntax,
|
71
|
+
:lint,
|
72
|
+
:unit
|
73
|
+
]
|
74
|
+
|
75
|
+
desc 'Run unit tests'
|
76
|
+
task unit: [
|
77
|
+
:r10k_install_modules,
|
78
|
+
:spec_prep,
|
79
|
+
:spec_standalone
|
80
|
+
]
|
81
|
+
|
82
|
+
desc 'Run acceptance tests'
|
83
|
+
task integration: [
|
84
|
+
:spec_prep,
|
85
|
+
:beaker
|
86
|
+
]
|
87
|
+
|
88
|
+
desc 'Clean all test files'
|
89
|
+
task clean: [:spec_clean]
|
90
|
+
|
91
|
+
desc 'Use R10K to download all modules'
|
92
|
+
task :r10k_install_modules do
|
93
|
+
r10k_install_modules
|
94
|
+
end
|
95
|
+
|
96
|
+
desc 'Generates a new .fixtures.yml from a Puppetfile'
|
97
|
+
task :generate_fixtures do
|
98
|
+
generate_fixtures
|
99
|
+
end
|
100
|
+
|
101
|
+
desc 'Print outdated Puppetfile modules'
|
102
|
+
task :puppetfile_inspect do
|
103
|
+
check_puppetfile_versions
|
104
|
+
end
|
105
|
+
end # def define_tasks
|
106
|
+
|
107
|
+
def puppetfile
|
108
|
+
@puppetfile ||= ::R10K::Puppetfile.new(pwd)
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_puppetfile
|
112
|
+
puppetfile.load
|
113
|
+
error 'Puppetfile was not found or is empty!' if puppetfile.modules.empty?
|
114
|
+
end
|
115
|
+
|
116
|
+
def r10k_install_modules
|
117
|
+
info 'Updating modules with R10K'
|
118
|
+
::R10K::CLI.command.run(%w(puppetfile install --force --verbose))
|
119
|
+
rescue SystemExit # because R10K::CLI.command.run calls `exit 0`
|
120
|
+
info 'Modules have been updated'
|
121
|
+
end
|
122
|
+
|
123
|
+
def generate_fixtures
|
124
|
+
info 'Generating fixtures file'
|
125
|
+
|
126
|
+
check_puppetfile
|
127
|
+
|
128
|
+
fixtures = {
|
129
|
+
'fixtures' => {
|
130
|
+
'symlinks' => {
|
131
|
+
'role' => '#{source_dir}/dist/role',
|
132
|
+
'profile' => '#{source_dir}/dist/profile'
|
133
|
+
},
|
134
|
+
'repositories' => {}
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
puppetfile.modules.each do |mod|
|
139
|
+
module_name = mod.title.tr('/', '-')
|
140
|
+
remote = mod.instance_variable_get('@remote')
|
141
|
+
ref = mod.instance_variable_get('@desired_ref')
|
142
|
+
|
143
|
+
fixtures['fixtures']['repositories'][module_name] = {
|
144
|
+
'repo' => remote,
|
145
|
+
'ref' => ref
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
File.open('.fixtures.yml', 'w') { |file| file.write(fixtures.to_yaml) }
|
150
|
+
info 'Done'
|
151
|
+
end # def generate_fixtures
|
152
|
+
|
153
|
+
def check_puppetfile_versions
|
154
|
+
puppetfile.load
|
155
|
+
error 'Puppetfile was not found or is empty!' if puppetfile.modules.empty?
|
156
|
+
|
157
|
+
puppetfile.modules.each do |mod|
|
158
|
+
if mod.class == ::R10K::Module::Forge
|
159
|
+
module_name = mod.title.tr('/', '-')
|
160
|
+
forge_version = ::PuppetForge::Module.find(module_name)
|
161
|
+
.current_release.version
|
162
|
+
installed_version = mod.expected_version
|
163
|
+
if installed_version != forge_version
|
164
|
+
puts "#{module_name} is OUTDATED: " \
|
165
|
+
"#{installed_version} vs #{forge_version}"
|
166
|
+
.red
|
167
|
+
else
|
168
|
+
puts "#{module_name}: #{forge_version}".green
|
169
|
+
end
|
170
|
+
elsif mod.class == ::R10K::Module::Git
|
171
|
+
# Try to extract owner and repo name from remote string
|
172
|
+
remote = mod.instance_variable_get('@remote')
|
173
|
+
owner = remote.gsub(%r{(.*)\/(.*)\/(.*)}, '\\2')
|
174
|
+
repo = remote.gsub(%r{(.*)\/(.*)\/}, '\\3')
|
175
|
+
|
176
|
+
# It's better to query the API authenticated because of the rate
|
177
|
+
# limit. You can make up to 5,000 requests per hour. For unauthenticated
|
178
|
+
# requests, the rate limit is only up to 60 requests per hour.
|
179
|
+
# (https://developer.github.com/v3/#rate-limiting)
|
180
|
+
tags = if GITHUB_TOKEN
|
181
|
+
open("https://api.github.com/repos/#{owner}/#{repo}/tags?access_token=#{GITHUB_TOKEN}")
|
182
|
+
else
|
183
|
+
open("https://api.github.com/repos/#{owner}/#{repo}/tags")
|
184
|
+
end
|
185
|
+
|
186
|
+
# Get rid of non-semantic versions (for example
|
187
|
+
# https://github.com/puppetlabs/puppetlabs-ntp/releases/tag/push)
|
188
|
+
all_tags = JSON.parse(tags.read).select do |tag|
|
189
|
+
tag['name'] =~ /v?\d+\.\d+\.\d+/
|
190
|
+
end
|
191
|
+
|
192
|
+
# Use Gem::Version to sort tags
|
193
|
+
latest_tag = all_tags.map do |line|
|
194
|
+
::Gem::Version.new line['name'].gsub(/[v]?(.*)/, '\\1')
|
195
|
+
end.max.to_s
|
196
|
+
|
197
|
+
# Print results
|
198
|
+
installed_version = mod.version.gsub(/[v]?(.*)/, '\\1')
|
199
|
+
if installed_version == 'master'
|
200
|
+
puts "#{mod.title}: 'master' branch (#{latest_tag})".blue
|
201
|
+
elsif installed_version != latest_tag
|
202
|
+
puts "#{mod.title} is OUTDATED: " \
|
203
|
+
"#{installed_version} vs #{latest_tag}"
|
204
|
+
.red
|
205
|
+
else
|
206
|
+
puts "#{mod.title}: #{latest_tag}".green
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end # def check_puppetfile_versions
|
211
|
+
end # class Puppet
|
212
|
+
end # module Vtasks
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Vtasks
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
# Release tasks
|
5
|
+
class Release < ::Rake::TaskLib
|
6
|
+
# Include utility modules
|
7
|
+
require 'vtasks/utils/git'
|
8
|
+
include Vtasks::Utils::Git
|
9
|
+
require 'vtasks/utils/output'
|
10
|
+
include Vtasks::Utils::Output
|
11
|
+
require 'vtasks/utils/semver'
|
12
|
+
include Vtasks::Utils::Semver
|
13
|
+
|
14
|
+
attr_reader :write_changelog,
|
15
|
+
:wait_for_ci_success,
|
16
|
+
:bug_labels,
|
17
|
+
:enhancement_labels
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
@write_changelog = options.fetch(:write_changelog, false)
|
21
|
+
@wait_for_ci_success = options.fetch(:wait_for_ci_success, false)
|
22
|
+
@bug_labels = options.fetch(:bug_labels, 'bug')
|
23
|
+
@enhancement_labels = options.fetch(:enhancement_labels, 'enhancement')
|
24
|
+
define_tasks
|
25
|
+
end
|
26
|
+
|
27
|
+
# Configure the github_changelog_generator/task
|
28
|
+
def changelog(config, release: nil)
|
29
|
+
config.bug_labels = bug_labels #'Type: Bug'
|
30
|
+
config.enhancement_labels = enhancement_labels #'Type: Enhancement'
|
31
|
+
config.future_release = "v#{release}" if release
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_tasks
|
35
|
+
desc "Release patch version"
|
36
|
+
task release: ['release:patch']
|
37
|
+
|
38
|
+
namespace :release do
|
39
|
+
begin
|
40
|
+
require 'github_changelog_generator/task'
|
41
|
+
|
42
|
+
# Create release:changes task
|
43
|
+
::GitHubChangelogGenerator::RakeTask.new(:changes) do |config|
|
44
|
+
changelog(config)
|
45
|
+
end
|
46
|
+
rescue LoadError
|
47
|
+
nil # Might be in a group that is not installed
|
48
|
+
end
|
49
|
+
|
50
|
+
SEM_LEVELS.each do |level|
|
51
|
+
desc "Release #{level} version"
|
52
|
+
task level.to_sym do
|
53
|
+
new_version = bump(level)
|
54
|
+
release = "#{new_version[:major]}.#{new_version[:minor]}.#{new_version[:patch]}"
|
55
|
+
release_branch = "release_v#{release.gsub(/[^0-9A-Za-z]/, '_')}"
|
56
|
+
initial_branch = git_branch
|
57
|
+
|
58
|
+
info 'Check if the repository is clean'
|
59
|
+
git_clean_repo
|
60
|
+
|
61
|
+
# Write changelog
|
62
|
+
# Create a separate release branch (works with protected branches as well)
|
63
|
+
if write_changelog == true
|
64
|
+
info 'Generate new changelog'
|
65
|
+
::GitHubChangelogGenerator::RakeTask.new(:latest_release) do |config|
|
66
|
+
changelog(config, release: release)
|
67
|
+
end
|
68
|
+
task('latest_release').invoke
|
69
|
+
|
70
|
+
if system 'git diff --quiet HEAD'
|
71
|
+
info 'CHANGELOG has not changed. Skipping...'
|
72
|
+
else
|
73
|
+
info 'Create a new release branch'
|
74
|
+
sh "git checkout -b #{release_branch}"
|
75
|
+
|
76
|
+
info 'Commit the new changes'
|
77
|
+
sh "git commit --gpg-sign --message 'Update change log for v#{release}' CHANGELOG.md"
|
78
|
+
|
79
|
+
info 'Push the new changes'
|
80
|
+
sh "git push --set-upstream origin #{release_branch}"
|
81
|
+
|
82
|
+
if wait_for_ci_success == true
|
83
|
+
info 'Waiting for CI to finish'
|
84
|
+
sleep 5 until git_ci_status(release_branch) == 'success'
|
85
|
+
end
|
86
|
+
|
87
|
+
info 'Merge release branch'
|
88
|
+
sh "git checkout #{initial_branch}"
|
89
|
+
sh "git merge --gpg-sign --no-ff --message 'Release v#{release}' #{release_branch}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
info "Tag #{release}"
|
94
|
+
sh "git tag --sign v#{release} --message 'Release v#{release}'"
|
95
|
+
sh 'git push --follow-tags'
|
96
|
+
end # task
|
97
|
+
end # LEVELS
|
98
|
+
end # namespace :release
|
99
|
+
end # def define_tasks
|
100
|
+
end # class Release
|
101
|
+
end # module Vtasks
|