buildizer 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/buildizer/cli.rb CHANGED
@@ -1,64 +1,4 @@
1
1
  module Buildizer
2
- class Cli < ::Thor
3
- class << self
4
- def shared_options
5
- (@shared_options || {}).each do |name, options|
6
- method_option name, options
7
- end
8
- end
9
-
10
- def construct_packager(options)
11
- Packager.new(options: {'latest' => options['latest']}, debug: options['debug'])
12
- end
13
- end # << self
14
-
15
- @shared_options = {
16
- debug: {type: :boolean, default: false, desc: "turn on live logging for external commands"},
17
- }
18
-
19
- desc "init", "Initialize settings (.travis.yml, .buildizer.yml, git pre-commit hook)"
20
- shared_options
21
- method_option :latest,
22
- type: :boolean,
23
- desc: "use buildizer github master branch"
24
- def init
25
- self.class.construct_packager(options).init!
26
- end
27
-
28
- desc "update", "Regenerate .travis.yml"
29
- shared_options
30
- def update
31
- self.class.construct_packager(options).update!
32
- end
33
-
34
- desc "deinit", "Deinitialize settings (.buildizer.yml, git pre-commit hook)"
35
- shared_options
36
- def deinit
37
- self.class.construct_packager(options).deinit!
38
- end
39
-
40
- desc "prepare", "Prepare images for building packages"
41
- shared_options
42
- def prepare
43
- self.class.construct_packager(options).prepare!
44
- end
45
-
46
- desc "build", "Build packages"
47
- shared_options
48
- def build
49
- self.class.construct_packager(options).build!
50
- end
51
-
52
- desc "deploy", "Deploy packages"
53
- shared_options
54
- def deploy
55
- self.class.construct_packager(options).deploy!
56
- end
57
-
58
- desc "verify", "Verify targets params"
59
- shared_options
60
- def verify
61
- self.class.construct_packager(options).verify!
62
- end
2
+ module Cli
63
3
  end # Cli
64
4
  end # Buildizer
@@ -32,9 +32,9 @@ module Buildizer
32
32
 
33
33
  def with_cache(&blk)
34
34
  warn("No docker cache account settings " +
35
- "(BUILDIZER_DOCKER_CACHE, BUILDIZER_DOCKER_CACHE_USERNAME, " +
36
- "BUILDIZER_DOCKER_CACHE_PASSWORD, BUILDIZER_DOCKER_CACHE_EMAIL, " +
37
- "BUILDIZER_DOCKER_CACHE_SERVER) [WARN]") unless cache
35
+ "(BUILDIZER_DOCKER_CACHE, BUILDIZER_DOCKER_CACHE_USERNAME," +
36
+ " BUILDIZER_DOCKER_CACHE_PASSWORD, BUILDIZER_DOCKER_CACHE_EMAIL," +
37
+ " BUILDIZER_DOCKER_CACHE_SERVER) [WARN]") unless cache
38
38
 
39
39
  cache_login! if cache
40
40
  begin
@@ -49,7 +49,7 @@ module Buildizer
49
49
 
50
50
  cmd = ["docker login"]
51
51
  cmd << "--email=#{cache[:email]}" if cache[:email]
52
- cmd << "--username=#{cache[:username]}" if cache[:username]
52
+ cmd << "--username=#{cache[:user]}" if cache[:user]
53
53
  cmd << "--password=#{cache[:password]}" if cache[:password]
54
54
  cmd << "--server=#{cache[:server]}" if cache[:server]
55
55
  builder.packager.command! cmd.join(' '), desc: "Docker cache account login"
@@ -61,16 +61,30 @@ module Buildizer
61
61
  end
62
62
 
63
63
  def pull_image(image)
64
- builder.packager.command!("docker pull #{image.base_image}",
65
- desc: "Docker pull #{image.base_image}")
66
-
67
- builder.packager.command("docker pull #{image.name}",
68
- desc: "Docker pull #{image.name}") if cache
64
+ builder.packager.command! "docker pull #{image.base_image}", desc: "Pull docker base image #{image.base_image}"
65
+ if cache
66
+ pull_cache_res = builder.packager.command(
67
+ "docker pull #{image.cache_name}",
68
+ desc: "Try to pull docker cache image #{image.cache_name}"
69
+ )
70
+ if pull_cache_res.status.success?
71
+ builder.packager.command! "docker tag -f #{image.cache_name} #{image.name}",
72
+ desc: "Tag cache image #{image.cache_name}" +
73
+ " as prepared build image #{image.name}"
74
+ builder.packager.command! "docker rmi #{image.cache_name}",
75
+ desc: "Remove cache image #{image.cache_name}"
76
+ end
77
+ end
69
78
  end
70
79
 
71
80
  def push_image(image)
72
- builder.packager.command("docker push #{image.name}",
73
- desc: "Docker push #{image.name}") if cache
81
+ if cache
82
+ builder.packager.command! "docker tag -f #{image.name} #{image.cache_name}",
83
+ desc: "Tag prepared build image #{image.name}" +
84
+ " as cache image #{image.cache_name}"
85
+ builder.packager.command! "docker push #{image.cache_name}",
86
+ desc: "Push cache image #{image.cache_name}"
87
+ end
74
88
  end
75
89
 
76
90
  def build_image!(target)
@@ -78,7 +92,7 @@ module Buildizer
78
92
 
79
93
  target.image_work_path.join('Dockerfile').write [*target.image.instructions, nil].join("\n")
80
94
  builder.packager.command! "docker build -t #{target.image.name} #{target.image_work_path}",
81
- desc: "Docker build image #{target.image.name}"
95
+ desc: "Build docker image #{target.image.name}"
82
96
 
83
97
  push_image target.image
84
98
  end
@@ -48,6 +48,10 @@ module Buildizer
48
48
  target.docker_image
49
49
  end
50
50
 
51
+ def cache_name
52
+ target.docker_cache_image
53
+ end
54
+
51
55
  def instruction(instruction, cmd)
52
56
  instructions << [instruction.to_s.upcase, cmd].join(' ')
53
57
  end
@@ -0,0 +1,63 @@
1
+ module Buildizer
2
+ class Packager
3
+ module BuildizerConfMod
4
+ using Refine
5
+
6
+ def buildizer_conf_path
7
+ package_path.join('Buildizer')
8
+ end
9
+
10
+ def buildizer_conf
11
+ @buildizer_conf ||= buildizer_conf_path.load_yaml
12
+ end
13
+
14
+ def buildizer_conf_update(conf)
15
+ buildizer_conf.update conf
16
+ end
17
+
18
+ def buildizer_conf_setup!
19
+ write_path(buildizer_conf_path, YAML.dump(buildizer_conf))
20
+ end
21
+
22
+ def package_name
23
+ buildizer_conf['package_name']
24
+ end
25
+
26
+ def package_version
27
+ buildizer_conf['package_version']
28
+ end
29
+
30
+ def before_prepare
31
+ Array(buildizer_conf['before_prepare'])
32
+ end
33
+
34
+ def after_prepare
35
+ Array(buildizer_conf['after_prepare'])
36
+ end
37
+
38
+ def targets
39
+ targets = Array(buildizer_conf['target'])
40
+ restrict_targets = ENV['BUILDIZER_TARGET']
41
+ restrict_targets = restrict_targets.split(',').map(&:strip) if restrict_targets
42
+ targets = targets & restrict_targets if restrict_targets
43
+ targets
44
+ end
45
+
46
+ def prepare
47
+ Array(buildizer_conf['prepare'])
48
+ end
49
+
50
+ def build_dep
51
+ Array(buildizer_conf['build_dep']).to_set
52
+ end
53
+
54
+ def before_build
55
+ Array(buildizer_conf['before_build'])
56
+ end
57
+
58
+ def maintainer
59
+ buildizer_conf['maintainer']
60
+ end
61
+ end # BuildizerConfMod
62
+ end # Packager
63
+ end # Buildizer
@@ -0,0 +1,27 @@
1
+ module Buildizer
2
+ class Packager
3
+ module CiMod
4
+ def ci_name
5
+ @ci_name ||= begin
6
+ case git_remote_url.to_s
7
+ when /github/
8
+ 'travis'
9
+ when /gitlab/
10
+ 'gitlab-ci'
11
+ else
12
+ raise Error, error: :input_error, message: "unable to determine ci to use"
13
+ end
14
+ end
15
+ end
16
+
17
+ def ci
18
+ @ci ||= begin
19
+ klass = {'travis' => Ci::Travis,
20
+ 'gitlab-ci' => Ci::GitlabCi}[ci_name.to_s.downcase]
21
+ raise Error, message: "unknown ci '#{ci_name}'" unless klass
22
+ klass.new(self)
23
+ end
24
+ end
25
+ end # CiMod
26
+ end # Packager
27
+ end # Buildizer
@@ -0,0 +1,103 @@
1
+ module Buildizer
2
+ class Packager
3
+ module DockerCacheMod
4
+ def docker_cache
5
+ return unless repo = ENV['BUILDIZER_DOCKER_CACHE']
6
+ {user: ENV['BUILDIZER_DOCKER_CACHE_USERNAME'],
7
+ password: ENV['BUILDIZER_DOCKER_CACHE_PASSWORD'],
8
+ email: ENV['BUILDIZER_DOCKER_CACHE_EMAIL'],
9
+ server: ENV['BUILDIZER_DOCKER_CACHE_SERVER'],
10
+ repo: repo}
11
+ end
12
+
13
+ def setup_docker_cache_repo
14
+ cli.options['docker_cache']
15
+ end
16
+
17
+ def setup_docker_cache_org
18
+ setup_docker_cache_repo.split('/').first
19
+ end
20
+
21
+ def setup_docker_cache_user
22
+ cli.options['docker_cache_user'] || user_settings_docker_cache_user_list(setup_docker_cache_org).first
23
+ end
24
+
25
+ def setup_docker_cache_password
26
+ @setup_docker_cache_password ||= begin
27
+ settings_password = user_settings_docker_cache_user(setup_docker_cache_user)['password']
28
+ if cli.options['reset_docker_cache_password'] or settings_password.nil?
29
+ cli.ask("Docker cache user '#{setup_docker_cache_user}' password:", echo: false).tap{puts}
30
+ else
31
+ settings_password
32
+ end
33
+ end
34
+ end
35
+
36
+ def setup_docker_cache_email
37
+ cli.options['docker_cache_email'] || user_settings_docker_cache_user(setup_docker_cache_user)['email']
38
+ end
39
+
40
+ def setup_docker_cache_server
41
+ cli.options['docker_cache_server'] || user_settings_docker_cache_user(setup_docker_cache_user)['server']
42
+ end
43
+
44
+ def user_settings_docker_cache
45
+ user_settings['docker_cache'] ||= {}
46
+ end
47
+
48
+ def user_settings_docker_cache_org(org)
49
+ user_settings_docker_cache['org'] ||= {}
50
+ user_settings_docker_cache['org'][org] ||= {}
51
+ end
52
+
53
+ def user_settings_docker_cache_user(user)
54
+ user_settings_docker_cache['user'] ||= {}
55
+ user_settings_docker_cache['user'][user] ||= {}
56
+ end
57
+
58
+ def user_settings_docker_cache_user_list(org)
59
+ user_settings_docker_cache_org(org)['user'] ||= []
60
+ end
61
+
62
+ def user_settings_docker_cache_repo_list(org)
63
+ user_settings_docker_cache_org(org)['repo'] ||= []
64
+ end
65
+
66
+ def docker_cache_update_settings?
67
+ not setup_docker_cache_repo.nil?
68
+ end
69
+
70
+ def docker_cache_clear_settings?
71
+ cli.options['clear_docker_cache']
72
+ end
73
+
74
+ def docker_cache_setup!
75
+ if docker_cache_update_settings?
76
+ raise Error, error: :input_error,
77
+ message: "docker cache user required" unless setup_docker_cache_user
78
+ raise Error, error: :input_error,
79
+ message: "bad docker cache user" if setup_docker_cache_user.empty?
80
+
81
+ user_list = user_settings_docker_cache_user_list(setup_docker_cache_org)
82
+ user_list.push(setup_docker_cache_user) unless user_list.include? setup_docker_cache_user
83
+
84
+ raise Error, error: :input_error,
85
+ message: 'docker cache email required' unless setup_docker_cache_email
86
+ raise Error, error: :input_error,
87
+ message: "bad docker cache email" unless setup_docker_cache_email =~ /.+@.+/
88
+
89
+ user_settings_docker_cache_user(setup_docker_cache_user)['email'] = setup_docker_cache_email
90
+ user_settings_docker_cache_user(setup_docker_cache_user)['server'] = setup_docker_cache_server
91
+ user_settings_docker_cache_user(setup_docker_cache_user)['password'] = setup_docker_cache_password
92
+
93
+ repo_list = user_settings_docker_cache_repo_list(setup_docker_cache_org)
94
+ repo_list.push(setup_docker_cache_repo) unless repo_list.include? setup_docker_cache_repo
95
+
96
+ user_settings_save!
97
+ end
98
+
99
+ ci.docker_cache_setup!
100
+ end
101
+ end # DockerCacheMod
102
+ end # Packager
103
+ end # Buildizer
@@ -0,0 +1,16 @@
1
+ module Buildizer
2
+ class Packager
3
+ module GitMod
4
+ def git_available?
5
+ res = raw_command 'git status'
6
+ res.status.success?
7
+ end
8
+
9
+ def git_remote_url
10
+ return unless git_available?
11
+ res = raw_command 'git config --get remote.origin.url'
12
+ res.stdout.strip
13
+ end
14
+ end # GitMod
15
+ end # Packager
16
+ end # Buildizer
@@ -0,0 +1,61 @@
1
+ module Buildizer
2
+ class Packager
3
+ module MiscMod
4
+ def command(*args, do_raise: false, log_failure: nil, **kwargs)
5
+ if debug
6
+ Shellfold.run(*args, log_failure: log_failure, **kwargs).tap do |cmd|
7
+ if not cmd.status.success? and do_raise
8
+ raise Error.new(error: :error, message: "external command error")
9
+ end
10
+ end
11
+ else
12
+ raw_command(*args, do_raise: do_raise, **kwargs)
13
+ end
14
+ end
15
+
16
+ def command!(*args, **kwargs)
17
+ command(*args, do_raise: true, log_failure: true, **kwargs)
18
+ end
19
+
20
+ def raw_command(*args, do_raise: false, **kwargs)
21
+ Mixlib::ShellOut.new(*args, **kwargs).tap do |cmd|
22
+ cmd.run_command
23
+ if not cmd.status.success? and do_raise
24
+ raise Error.new(error: :error,
25
+ message: "external command error: " +
26
+ [args.join(' '),
27
+ cmd.stdout + cmd.stderr].reject(&:empty?).join(' => '))
28
+ end
29
+ end
30
+ end
31
+
32
+ def raw_command!(*args, **kwargs)
33
+ raw_command(*args, do_raise: true, **kwargs)
34
+ end
35
+
36
+ def write_path(path, value)
37
+ with_log(desc: "Write path #{path}") do |&fin|
38
+ recreate = path.exist?
39
+ if path.exist?
40
+ if path.read == value
41
+ fin.call 'OK'
42
+ else
43
+ path.write value
44
+ fin.call 'UPDATED'
45
+ end
46
+ else
47
+ path.write value
48
+ fin.call 'CREATED'
49
+ end
50
+ end
51
+ end
52
+
53
+ def with_log(desc: nil, &blk)
54
+ puts(" #{desc}") if debug and desc
55
+ blk.call do |status|
56
+ puts("=> #{desc} [#{status || 'OK'}]") if debug and desc
57
+ end
58
+ end
59
+ end # MiscMod
60
+ end # Packager
61
+ end # Buildizer
@@ -0,0 +1,85 @@
1
+ module Buildizer
2
+ class Packager
3
+ module OvercommitMod
4
+ using Refine
5
+
6
+ def overcommit_conf_path
7
+ package_path.join('.overcommit.yml')
8
+ end
9
+
10
+ def overcommit_hooks_path
11
+ package_path.join('.git-hooks')
12
+ end
13
+
14
+ def overcommit_hooks_pre_commit_path
15
+ overcommit_hooks_path.join('pre_commit')
16
+ end
17
+
18
+ def overcommit_conf
19
+ @overcommit_conf ||= overcommit_conf_path.load_yaml
20
+ end
21
+
22
+ def overcommit_conf_raw
23
+ YAML.dump(overcommit_conf)
24
+ end
25
+
26
+ def overcommit_conf_dump!
27
+ write_path overcommit_conf_path, overcommit_conf_raw
28
+ command! 'overcommit --sign'
29
+ end
30
+
31
+ def overcommit_setup!
32
+ overcommit_hooks_path.mkpath
33
+ overcommit_conf_dump!
34
+ command! 'overcommit --install'
35
+ end
36
+
37
+ def overcommit_verify_setup!
38
+ hookcode = <<-HOOKCODE
39
+ module Overcommit::Hook::PreCommit
40
+ class BuildizerVerify < Base
41
+ def run
42
+ return :fail unless system("buildizer verify")
43
+ :pass
44
+ end
45
+ end
46
+ end
47
+ HOOKCODE
48
+
49
+ _overcommit_add_precommit!(:buildizer_verify, hookcode, desc: "Verify Buildizer conf file")
50
+ end
51
+
52
+ def overcommit_ci_setup!
53
+ hookcode = <<-HOOKCODE
54
+ module Overcommit::Hook::PreCommit
55
+ class BuildizerCiVerify < Base
56
+ def run
57
+ return :fail unless system("buildizer setup --verify-ci")
58
+ :pass
59
+ end
60
+ end
61
+ end
62
+ HOOKCODE
63
+
64
+ _overcommit_add_precommit!(:buildizer_ci_verify, hookcode,
65
+ desc: "Verify #{ci.ci_name} configuration is up to date")
66
+ end
67
+
68
+ def _overcommit_add_precommit!(name, hookcode, desc: nil, required: true)
69
+ hook_name = name.to_s.split('_').map(&:capitalize).join
70
+ overcommit_conf['PreCommit'] ||= {}
71
+ overcommit_conf['PreCommit'][hook_name] = {}.tap do |hook|
72
+ hook['enabled'] = true
73
+ hook['required'] = required
74
+ hook['desc'] = desc if desc
75
+ end
76
+ overcommit_conf_dump!
77
+
78
+ overcommit_hooks_pre_commit_path.mkpath
79
+ path = overcommit_hooks_pre_commit_path.join("#{name}.rb")
80
+ write_path path, hookcode
81
+ command! 'overcommit --sign pre-commit'
82
+ end
83
+ end # OvercommitMod
84
+ end # Packager
85
+ end # Buildizer
@@ -0,0 +1,81 @@
1
+ module Buildizer
2
+ class Packager
3
+ module PackageCloudMod
4
+ def package_cloud_repo
5
+ ENV['PACKAGECLOUD'].to_s.split(',')
6
+ end
7
+
8
+ def package_cloud_org
9
+ default_token = ENV['PACKAGECLOUD_TOKEN']
10
+ package_cloud_repo.map {|repo| repo.split('/').first}.uniq.map do |org|
11
+ [org, ENV["PACKAGECLOUD_TOKEN_#{org.upcase}"] || default_token]
12
+ end.to_h
13
+ end
14
+
15
+ def package_cloud
16
+ tokens = package_cloud_org
17
+ package_cloud_repo.map do |repo|
18
+ org = repo.split('/').first
19
+ token = tokens[org]
20
+ {org: org, repo: repo, token: token}
21
+ end
22
+ end
23
+
24
+ def user_settings_package_cloud
25
+ user_settings['package_cloud'] ||= {}
26
+ end
27
+
28
+ def user_settings_package_cloud_token
29
+ user_settings_package_cloud['token'] ||= {}
30
+ end
31
+
32
+ def setup_package_cloud_repo_list
33
+ Array(cli.options['package_cloud']).uniq
34
+ end
35
+
36
+ def setup_package_cloud_repo_desc_list
37
+ setup_package_cloud_repo_list.map do |repo|
38
+ org, name = repo.split('/')
39
+ {repo: repo, org: org, name: name, token: user_settings_package_cloud_token[org]}
40
+ end
41
+ end
42
+
43
+ def setup_package_cloud_org_desc_list
44
+ setup_package_cloud_repo_desc_list.map {|desc| {org: desc[:org], token: desc[:token]}}.uniq
45
+ end
46
+
47
+ def setup_package_cloud_org_list
48
+ setup_package_cloud_repo_desc_list.map {|desc| desc[:org]}.uniq
49
+ end
50
+
51
+ def package_cloud_update_settings?
52
+ cli.options['package_cloud']
53
+ end
54
+
55
+ def package_cloud_clear_settings?
56
+ cli.options['clear_package_cloud']
57
+ end
58
+
59
+ def package_cloud_setup!
60
+ if package_cloud_update_settings?
61
+ update_user_settings = false
62
+ setup_package_cloud_org_list.each do |org|
63
+ if user_settings_package_cloud_token[org].nil? or
64
+ cli.options['reset_package_cloud_token']
65
+ token = cli.ask("Enter token for package_cloud org '#{org}':",
66
+ echo: false, default: 'none').tap{puts}
67
+ token = (token == 'none' ? nil : token)
68
+ if user_settings_package_cloud_token[org] != token
69
+ user_settings_package_cloud_token[org] = token
70
+ update_user_settings = true
71
+ end
72
+ end
73
+ end
74
+ user_settings_save! if update_user_settings
75
+ end
76
+
77
+ ci.package_cloud_setup!
78
+ end
79
+ end # PackageCloudMod
80
+ end # Packager
81
+ end # Buildizer
@@ -0,0 +1,15 @@
1
+ module Buildizer
2
+ class Packager
3
+ module PackageVersionTagMod
4
+ using Refine
5
+
6
+ def package_version_tag_required_for_deploy?
7
+ ENV['BUILDIZER_REQUIRE_TAG'].to_s.on?
8
+ end
9
+
10
+ def package_version_tag
11
+ ci.git_tag
12
+ end
13
+ end # PackageVersionTagMod
14
+ end # Packager
15
+ end # Buildizer
@@ -0,0 +1,27 @@
1
+ module Buildizer
2
+ class Packager
3
+ module ProjectSettingsMod
4
+ using Refine
5
+
6
+ def project_settings_path
7
+ package_path.join('.buildizer.yml')
8
+ end
9
+
10
+ def project_settings
11
+ @project_settings ||= begin
12
+ (project_settings_path.load_yaml || {}).tap do |settings|
13
+ settings['master'] = cli.options['master'] if cli.options.key? 'master'
14
+ end
15
+ end
16
+ end
17
+
18
+ def project_settings_save!
19
+ write_path(project_settings_path, YAML.dump(project_settings))
20
+ end
21
+
22
+ def project_settings_setup!
23
+ project_settings_save!
24
+ end
25
+ end # ProjectSettingsMod
26
+ end # Packager
27
+ end # Buildizer
@@ -0,0 +1,24 @@
1
+ module Buildizer
2
+ class Packager
3
+ module UserSettingsMod
4
+ using Refine
5
+
6
+ def user_settings_path
7
+ work_path.join('settings.yml')
8
+ end
9
+
10
+ def user_settings
11
+ @user_settings ||= (user_settings_path.load_yaml || {})
12
+ end
13
+
14
+ def user_settings_save!
15
+ write_path(user_settings_path, YAML.dump(user_settings))
16
+ user_settings_path.chmod(0600)
17
+ end
18
+
19
+ def user_settings_setup!
20
+ user_settings_save!
21
+ end
22
+ end # UserSettingsMod
23
+ end # Packager
24
+ end # Buildizer