Class: Dash::Report
- Inherits:
-
Object
- Object
- Dash::Report
- Defined in:
- lib/dash/report.rb
Overview
The deploy report: the phase table plus everything measured inside a phase that the table itself has no column for. Today that is the build; the Dockerfile advice and the JSON export hang off the same object.
It owns the rendering rather than Timings because the build rows have to be spliced into the middle of the table, under the phase they belong to, and Timings has no business knowing what a buildx vertex is.
Defined Under Namespace
Classes: History, Trends, Writer
Constant Summary collapse
- INDENT =
Depth-1 rows, so build steps line up with the per-host rows a Boot phase prints.
" "- NAME_WIDTH =
Wider than the phase table's 36-column name, because a Dockerfile instruction is the whole point of the row and most of them are longer than that. The build rows line up with each other as their own block under the phase; 4 + 60 + 8 still fits 80 columns.
60- VALUE_WIDTH =
7- SLOWEST_STEPS =
5- SEVERITY_WIDTH =
Severity, then the file or key to open, then the sentence. The suggestion hangs under the sentence so the eye can skip the whole block or read one finding in full.
4- LOCATION_WIDTH =
15- SEVERITY_COLORS =
{ warn: "\e[33m" }.freeze
- SCHEMA =
The version of the JSON documents #to_h writes and #from_h reads. Bumping it is a promise to whatever reads .dash/reports, so a reader that does not recognise the number skips the file rather than guessing.
1
Instance Attribute Summary collapse
-
#advice ⇒ Object
Returns the value of attribute advice.
-
#build ⇒ Object
Returns the value of attribute build.
-
#build_entry ⇒ Object
Returns the value of attribute build_entry.
-
#timings ⇒ Object
readonly
Returns the value of attribute timings.
Class Method Summary collapse
-
.from_h(document) ⇒ Object
Rebuilds a saved report so
dash reportprints it the way the deploy printed it — same table, same build rows under the same phase, same advice.
Instance Method Summary collapse
-
#advice_lines ⇒ Object
Also printed on their own by
dash build push, for the same reason the build rows are. -
#analyze!(config, build: @build, build_directory: config.builder.build_directory) ⇒ Object
Runs the Dockerfile rules against the file this deploy would build, upgraded with what the build measured when there was one.
-
#build_lines ⇒ Object
Also printed on their own by
dash build push, which has no phase table to sit under. -
#initialize(timings:) ⇒ Report
constructor
A new instance of Report.
- #lines ⇒ Object
-
#to_h(**run) ⇒ Object
The run's own facts (command, service, destination, version, timings of the whole thing) belong to the caller that knows them; the report contributes what it measured.
Constructor Details
#initialize(timings:) ⇒ Report
Returns a new instance of Report.
50 51 52 53 |
# File 'lib/dash/report.rb', line 50 def initialize(timings:) @timings = timings @advice = [] end |
Instance Attribute Details
#advice ⇒ Object
Returns the value of attribute advice.
35 36 37 |
# File 'lib/dash/report.rb', line 35 def advice @advice end |
#build ⇒ Object
Returns the value of attribute build.
35 36 37 |
# File 'lib/dash/report.rb', line 35 def build @build end |
#build_entry ⇒ Object
Returns the value of attribute build_entry.
35 36 37 |
# File 'lib/dash/report.rb', line 35 def build_entry @build_entry end |
#timings ⇒ Object (readonly)
Returns the value of attribute timings.
34 35 36 |
# File 'lib/dash/report.rb', line 34 def timings @timings end |
Class Method Details
.from_h(document) ⇒ Object
Rebuilds a saved report so dash report prints it the way the deploy printed it —
same table, same build rows under the same phase, same advice.
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/dash/report.rb', line 39 def self.from_h(document) document = document.transform_keys(&:to_sym) timings = Dash::Timings.from_h(document[:phases]) new(timings: timings).tap do |report| report.build_entry = timings.entry_at(document[:build_phase]) report.build = Dash::Build::Report.from_h(document[:build]) if document[:build] report.advice = Array(document[:advice]).map { |finding| Dash::Dockerfile::Finding.from_h(finding) } end end |
Instance Method Details
#advice_lines ⇒ Object
Also printed on their own by dash build push, for the same reason the build rows are.
106 107 108 109 110 |
# File 'lib/dash/report.rb', line 106 def advice_lines return [] if advice.blank? [ " Advice", *advice.flat_map { |finding| advice_rows(finding) } ] end |
#analyze!(config, build: @build, build_directory: config.builder.build_directory) ⇒ Object
Runs the Dockerfile rules against the file this deploy would build, upgraded with what
the build measured when there was one. Silent about a Dockerfile that is not there:
a --skip-push deploy never looks at one, and a missing file is dash doctor's finding
to report, not a deploy's.
build_directory is where the Dockerfile and context are read from: the git clone for
a push, the working directory for a dev build that never clones.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/dash/report.rb', line 86 def analyze!(config, build: @build, build_directory: config.builder.build_directory) @advice = [] return unless config.report.advice? dockerfile = File.(config.builder.dockerfile, build_directory) return unless File.exist?(dockerfile) @advice = Dash::Dockerfile::Analyzer.new( document: Dash::Dockerfile::Parser.parse(File.read(dockerfile)), path: config.builder.dockerfile, file: dockerfile, context_dir: File.(config.builder.context, build_directory), build: build, builder: config.builder, ignore: config.report.ignore, hadolint: config.report.hadolint? ).findings end |
#build_lines ⇒ Object
Also printed on their own by dash build push, which has no phase table to sit under.
113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/dash/report.rb', line 113 def build_lines return [] unless build&.any? rows = [] rows << context_row if build.context_bytes build.slowest(SLOWEST_STEPS).select(&:seconds).each { |step| rows << row(step.label, seconds(step.seconds)) } rows << row("cached steps", "#{build.cached_steps.size} of #{build.dockerfile_steps.size}") if build.dockerfile_steps.any? rows << export_row if export_and_push_seconds > 0 # A multi-platform build runs the same instruction once per platform, so one broken # step fails once per platform with the same message. Print that once. build.failed_steps.uniq { |step| [ step.label, step.error ] }.each { |step| rows << row(step.label, "error", step.error) } rows end |
#lines ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/dash/report.rb', line 67 def lines lines = timings.lines rows = build_lines unless rows.empty? index = build_entry && timings.index_of(build_entry) lines = index ? lines.insert(index + 1, *rows) : lines + rows end lines + advice_lines end |
#to_h(**run) ⇒ Object
The run's own facts (command, service, destination, version, timings of the whole
thing) belong to the caller that knows them; the report contributes what it measured.
build_phase is the row the build rows hang under, by position, so a reader can put
them back without matching on a phase name dash is free to reword.
59 60 61 62 63 64 65 |
# File 'lib/dash/report.rb', line 59 def to_h(**run) { schema: SCHEMA, dash_version: Dash::VERSION, **run, phases: timings.to_h, build_phase: build_entry && timings.index_of(build_entry), build: build&.to_h, advice: advice.map(&:to_h) }.compact end |