Class: Dctl::Main

Inherits:
Object
  • Object
show all
Defined in:
lib/dctl/main.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env: "dev") ⇒ Main

Returns a new instance of Main.



5
6
7
8
# File 'lib/dctl/main.rb', line 5

def initialize(env: "dev")
  @env = env
  load_config!
end

Instance Attribute Details

#env ⇒ Object (readonly)

Returns the value of attribute env.



3
4
5
# File 'lib/dctl/main.rb', line 3

def env
  @env
end

#settings ⇒ Object (readonly)

Returns the value of attribute settings.



3
4
5
# File 'lib/dctl/main.rb', line 3

def settings
  @settings
end

Instance Method Details

#check_image(image) ⇒ Object

Confirms that there is an entry for the given image in the compose file for this environment, and that the image tag within is formatted as we expect it to be.

Prints a warning if the tag has the wrong name, but errors out if the service tag is not present

Expected names look like org/project-env-image:version



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/dctl/main.rb', line 93

def check_image(image)
  tag = image_tag(image)

  # Check that a service exists for the image
  service = parsed_compose_file.dig "services", image
  unless service
    error = "The service \"#{image}\" is not present in the compose " \
      "file for this environment. Please add a service entry for " \
      "#{image} to #{compose_file_path}\n"
    puts Rainbow(error).fg :red

    puts "      It might look something like this:\n\n      version: '3'\n      services:\n        \#{image}:\n          image: \#{image_tag(image)}\n    EOL\n    exit 1\n  end\n\n  # Check that the image has the correct tag\n  expected_tag = image_tag(image)\n  actual_tag = service[\"image\"]\n  if actual_tag != expected_tag\n    warning = \"Expected the tag for the image \\\"\#{image}\\\" to be \" \\\n      \"\\\"\#{expected_tag}\\\", but it was \\\"\#{actual_tag}\\\". While not \" \\\n      \"critical, this can cause issues with some commands.\"\n    puts Rainbow(warning).fg :orange\n  end\nend\n"

#check_settings! ⇒ Object

Ensure the current project's .dctl.yml contains all the requisite keys.



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/dctl/main.rb', line 145

def check_settings!
  required_keys = %w(
    org
    project
  )

  required_keys.each do |key|
    unless Settings.send key
      error = "Config is missing required key '#{key}'. Please add it " \
        "to #{config_path} and try again."
      error += "\n\nFor more info, see https://github.com/jutonz/dctl_rb#required-keys"
      puts Rainbow(error).red
      exit 1
    end
  end
end

#compose_file_path ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/dctl/main.rb', line 172

def compose_file_path
  path = File.expand_path "docker/#{env}/docker-compose.yml"

  unless File.exist? path
    err = "There is no docker compose file for env #{env} (I expected to find it at #{path})"
    puts Rainbow(err).red
    exit 1
  end

  path
end

#config_path ⇒ Object

Returns the path to the .dctl.yml file for the current project



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/dctl/main.rb', line 72

def config_path
  path = File.expand_path ".dctl.yml", Dir.pwd

  unless File.exist? path
    error = "Could not find config file at #{path}"
    puts Rainbow(error).red
    exit 1
  end

  path
end

#expand_images(*images) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/dctl/main.rb', line 36

def expand_images(*images)
  images = versions.keys if images.empty?
  images = Array(images)

  images.each { |image| check_image(image) }

  images
end

#image_dir(image) ⇒ Object

Returns the path to the given image's data directory (which includes at minimum the Dockerfile, plus any other relevant files the user may have placed there).



27
28
29
30
# File 'lib/dctl/main.rb', line 27

def image_dir(image)
  relative = File.join "docker", env, image
  File.expand_path relative, Dir.pwd
end

#image_dockerfile(image) ⇒ Object



32
33
34
# File 'lib/dctl/main.rb', line 32

def image_dockerfile(image)
  File.expand_path "Dockerfile", image_dir(image)
end

#image_tag(image, version: versions[image]) ⇒ Object

Generate the full tag for the given image, concatenating the org, project, env, image name, and version.

Examples:

image_tag("app") # => jutonz/dctl-dev-app:1


16
17
18
19
20
21
# File 'lib/dctl/main.rb', line 16

def image_tag(image, version: versions[image])
  org       = settings.org
  project   = settings.project

  "#{org}/#{project}-#{env}-#{image}:#{version}"
end

#load_config! ⇒ Object

Load the current project's config file, complaining if it does not exist or is malformed.



165
166
167
168
169
170
# File 'lib/dctl/main.rb', line 165

def load_config!
  Config.load_and_set_settings(config_path)
  check_settings!

  @settings = Settings
end

#parsed_compose_file ⇒ Object



139
140
141
# File 'lib/dctl/main.rb', line 139

def parsed_compose_file
  @parsed_compose_file ||= YAML.load_file compose_file_path
end

#release(image) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/dctl/main.rb', line 45

def release(image)
  check_image(image)

  parsed  = parsed_compose_file
  service = parsed.dig "services", image
  old_tag = service["image"]
  puts "Found existing image #{old_tag}"

  version = versions[image].to_i
  new_tag = image_tag image, version: version + 1
  puts "New tag will be #{new_tag}"

  service["image"] = new_tag

  print "Updating..."
  File.write(compose_file_path, parsed.to_yaml)
  puts "done"

  # Cache bust
  @parsed_compose_file = nil
  @versions = nil

  puts Rainbow("#{image} is now at version #{version + 1}").fg :green
end

#versions ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/dctl/main.rb', line 126

def versions
  @versions ||= begin
    images = parsed_compose_file["services"].keys
    version_map = {}

    images.each do |image|
      version_map[image] = parsed_compose_file["services"][image]["image"].split(":").last
    end

    version_map
  end
end