Rendering build details.json with Crystal

Reading time: about 2 minutes

This is a follow-up of my post on serving a general metadata json.

Solving this problem in Crystal provides a few subtle problems that Ruby doesn’t experience:

In this application the build details are rendered via docker build wrapper script identically to the script in my previous entry. In contrast, I don’t funnel the build details through a config object intermediary here.

Here’s what I came up with to render a /ping.json endpoint in a Lucky action.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# src/lib/build.cr
class Build
  DETAILS_FILE = "build_details.json"

  def self.details
    instance = @@instance ||= new
    instance.details
  end

  getter build_timestamp : String
  getter git_revision : String
  getter version : String

  def initialize
    if File.exists? DETAILS_FILE
      raw_file = File.read DETAILS_FILE
    else
      raw_file = "{}"
    end

    parsed_details = JSON.parse raw_file

    @build_timestamp = parsed_details["build_timestamp"]?.try(&.as_s?) || Time.utc.to_s
    @git_revision = parsed_details["git_revision"]?.try(&.as_s?) || "000000000"
    @version = parsed_details["version"]?.try(&.as_s?) || "development"
  end

  def details : Hash(String, String)
    {
      "build_timestamp" => @build_timestamp,
      "git_revision" => @git_revision,
      "version" => @version,
      "crystal_version" => Crystal::VERSION
    }
  end
end
1
2
3
4
5
6
7
8
9
10
class Home::Ping < BrowserAction
  get "/ping" do
    response = Hash(String, String).new
    response["ok"] = "true"

    response.merge! Build.details

    json response
  end
end

Date: 2022-Jan-28
Tags: crystal bash lucky docker build_details devops
Previous: Organizing files in a terraform codebase