Class: Shiplane::Build

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/shiplane/build.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sha, postfix:, tag_latest: false, stage: nil) ⇒ Build

Returns a new instance of Build.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/shiplane/build.rb', line 16

def initialize(sha, postfix:, tag_latest: false, stage: nil)
  @sha = sha
  @tag_latest = tag_latest
  @postfix = postfix
  @stage = stage
  @run_folder = Dir.pwd

  Dotenv.overload File.join(Dir.pwd, build_environment_filepath)

  # Add any ENV variable overrides from the capistrano configuration
  build_environment_variables = fetch(:shiplane_build_environment_variables, {})
  build_environment_variables.each do |key, value|
    if value.is_a? Proc
      ENV[key.to_s] = value.call
    else
      ENV[key.to_s] = value
    end
  end
end

Instance Attribute Details

#build_environment_variablesObject

Returns the value of attribute build_environment_variables.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def build_environment_variables
  @build_environment_variables
end

#postfixObject

Returns the value of attribute postfix.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def postfix
  @postfix
end

#run_folderObject

Returns the value of attribute run_folder.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def run_folder
  @run_folder
end

#shaObject

Returns the value of attribute sha.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def sha
  @sha
end

#stageObject

Returns the value of attribute stage.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def stage
  @stage
end

#tag_latestObject

Returns the value of attribute tag_latest.



12
13
14
# File 'lib/shiplane/build.rb', line 12

def tag_latest
  @tag_latest
end

Class Method Details

.build!(sha, postfix: nil, stage: nil) ⇒ Object

API Helper Methods



206
207
208
# File 'lib/shiplane/build.rb', line 206

def self.build!(sha, postfix: nil, stage: nil)
  new(sha, postfix: postfix, stage: stage).build!
end

.build_latest!(sha, postfix: nil, stage: nil) ⇒ Object



210
211
212
# File 'lib/shiplane/build.rb', line 210

def self.build_latest!(sha, postfix: nil, stage: nil)
  new(sha, postfix: postfix, tag_latest: true, stage: stage).build!
end

Instance Method Details

#appnameObject

Properties



121
122
123
# File 'lib/shiplane/build.rb', line 121

def appname
  @appname ||= project_config['appname']
end

#build!Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/shiplane/build.rb', line 36

def build!
  unless File.exist?(File.join(project_folder, Shiplane::SHIPLANE_CONFIG_FILENAME))
    Shiplane::CheckoutArtifact.checkout!(sha, config: shiplane_config)
    Shiplane::ConvertComposeFile.convert_output!(project_folder, sha, config: shiplane_config)
  end

  buildable_artifacts.each do |(artifact_name, attributes)|
    compose_context = docker_config.fetch('services', {}).fetch(artifact_name.to_s, {})
    Shiplane::ConvertDockerfile.convert_output!(project_folder, attributes, compose_context, config: shiplane_config)

    FileUtils.cd project_folder do
      steps(artifact_name, attributes).select{|step| step.fetch(:condition, true) }.each do |step|
        puts step[:notify_before] if step.has_key? :notify_before
        success = system(step[:command])
        raise StepFailureException.new(step[:command], artifact_name) unless success
        puts step[:notify_after] if step.has_key? :notify_after
      end
    end
  end
rescue StepFailureException => e
  puts e.message
  raise if ENV['RAISE_EXCEPTIONS_ON_FAILED_BUILD'] == 'true'
end

#build_cache_optionObject



195
196
197
# File 'lib/shiplane/build.rb', line 195

def build_cache_option
  ENV['USE_BUILD_CACHE'] == 'true' ? nil : "--no-cache"
end

#build_command(artifact_name) ⇒ Object

Commands



76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/shiplane/build.rb', line 76

def build_command(artifact_name)
  [
    'docker-compose',
    '-f',
    docker_compose_filepath,
    '--env-file',
    File.join(run_folder, build_environment_filepath),
    'build',
    build_cache_option,
    artifact_name,
  ].compact.join(' ')
end

#build_output_image_name(artifact_name) ⇒ Object



191
192
193
# File 'lib/shiplane/build.rb', line 191

def build_output_image_name(artifact_name)
  @build_output_image_name ||= "#{appname}-#{sha}#{docker_compose_separator}#{artifact_name}:latest"
end

#buildable_artifactsObject



145
146
147
# File 'lib/shiplane/build.rb', line 145

def buildable_artifacts
  build_config.fetch('artifacts', {})
end

#default_registry_configurationObject



149
150
151
152
153
154
# File 'lib/shiplane/build.rb', line 149

def default_registry_configuration
  {
    'url' => :dockerhub,
    'auth_method' => 'token',
  }
end

#docker_compose_filepathObject



137
138
139
# File 'lib/shiplane/build.rb', line 137

def docker_compose_filepath
  @docker_compose_filepath ||= File.join(project_folder, 'docker-compose.yml')
end

#docker_compose_separatorObject



199
200
201
202
203
# File 'lib/shiplane/build.rb', line 199

def docker_compose_separator
  return '_' if ENV['DOCKER_COMPOSE_V1_COMPATIBILITY'] && ENV['DOCKER_COMPOSE_V1_COMPATIBILITY'] == 'true'

  '-'
end

#docker_configObject



141
142
143
# File 'lib/shiplane/build.rb', line 141

def docker_config
  @docker_config ||= YAML.load(File.new(docker_compose_filepath))
end

#dockerhub?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/shiplane/build.rb', line 156

def dockerhub?
  registry_configuration['url'].to_s == 'dockerhub'
end

#login_tokenObject



179
180
181
182
183
# File 'lib/shiplane/build.rb', line 179

def 
  return ENV['DOCKERHUB_PASSWORD'] if dockerhub? && token_auth?

  ENV['SHIPLANE_CONTAINER_REGISTRY_TOKEN']
end

#login_usernameObject



185
186
187
188
189
# File 'lib/shiplane/build.rb', line 185

def 
  return ENV['DOCKERHUB_USERNAME'] if dockerhub? && token_auth?

  ENV['SHIPLANE_CONTAINER_REGISTRY_USERNAME']
end

#project_folderObject



129
130
131
# File 'lib/shiplane/build.rb', line 129

def project_folder
  @project_folder ||= File.join(run_folder, 'docker_builds', appname, project_folder_name)
end

#project_folder_nameObject



125
126
127
# File 'lib/shiplane/build.rb', line 125

def project_folder_name
  @project_folder_name ||= "#{appname}-#{sha}"
end

#push_command(attributes, tag = 'latest') ⇒ Object



112
113
114
115
116
117
118
# File 'lib/shiplane/build.rb', line 112

def push_command(attributes, tag='latest')
  [
    'docker',
    'push',
    "#{repo_name(attributes)}:#{tag}",
  ].compact.join(' ')
end

#registry_configurationObject



164
165
166
# File 'lib/shiplane/build.rb', line 164

def registry_configuration
  @registry_configuration ||= default_registry_configuration.merge(build_config.fetch('registry', {}))
end

#registry_urlObject



168
169
170
# File 'lib/shiplane/build.rb', line 168

def registry_url
  @registry_url ||= dockerhub? ? nil : registry_configuration['url']
end

#repo_name(attributes) ⇒ Object



172
173
174
175
176
177
# File 'lib/shiplane/build.rb', line 172

def repo_name(attributes)
  [
    registry_url,
    attributes['repo'],
  ].compact.join('/')
end

#shiplane_configObject



133
134
135
# File 'lib/shiplane/build.rb', line 133

def shiplane_config
  @shiplane_config ||= Shiplane::Configuration.new(stage: stage)
end

#steps(artifact_name, attributes) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/shiplane/build.rb', line 60

def steps(artifact_name, attributes)
  [
    { command: build_command(artifact_name), notify_before: "Building Artifact: #{artifact_name}...", notify_after: "Docker Compose Built", stop_on_failure: true },
    { command: tag_command(artifact_name, attributes, sha), notify_before: "Tagging Build [#{sha}]...", stop_on_failure: true },
    { command: tag_command(artifact_name, attributes, "#{postfix}-#{sha}"), notify_before: "Tagging Build [#{postfix}-#{sha}]...", stop_on_failure: true, condition: !!postfix },
    { command: tag_command(artifact_name, attributes, "#{postfix}-latest"), notify_before: "Tagging Build [#{postfix}-latest]...", stop_on_failure: true, condition: !!postfix && tag_latest },
    { command: tag_command(artifact_name, attributes), notify_before: "Tagging Build [latest]...", stop_on_failure: true, condition: tag_latest },
    { command:  , notify_before: "Logging into Container Registry...", stop_on_failure: true },
    { command: push_command(attributes, "#{sha}"), notify_before: "Pushing Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true },
    { command: push_command(attributes, "#{postfix}-#{sha}"), notify_before: "Pushing #{postfix} Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix },
    { command: push_command(attributes, "#{postfix}-latest"), notify_before: "Pushing Latest #{postfix} Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix && tag_latest },
    { command: push_command(attributes, "latest"), notify_before: "Pushing Latest Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: tag_latest },
  ]
end

#tag_command(artifact_name, attributes, tag = 'latest') ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/shiplane/build.rb', line 103

def tag_command(artifact_name, attributes, tag='latest')
  [
    'docker',
    'tag',
    build_output_image_name(artifact_name),
    "#{repo_name(attributes)}:#{tag}",
  ].compact.join(' ')
end

#token_auth?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/shiplane/build.rb', line 160

def token_auth?
  registry_configuration['auth_method'] == 'token'
end

#token_login_commandObject



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/shiplane/build.rb', line 89

def 
  @token_login_command ||= [
    'echo',
    "\"#{}\"",
    '|',
    'docker',
    'login',
    registry_url,
    '--username',
    ,
    '--password-stdin',
  ].compact.join(' ')
end