cartage-rack 1.1 → 2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1f756831e081111a68cf696035705057d5b06a8
4
- data.tar.gz: 5d02f8976aa4b7433e9c8d96c6ccc3558007e50b
3
+ metadata.gz: 94047d31b87bd33b0ede49ddc37cf6919449cfd4
4
+ data.tar.gz: 129d78a6a5cf83122b5a3581efdc446f9462688c
5
5
  SHA512:
6
- metadata.gz: da2f68e98d8ae476143c955ea2e8e1921b89890491a5b7ed41746bf518c42a8c9c26cb824397bfe4557c67da3686826ffd4f2b24f3023c2d90dd76e002f84d57
7
- data.tar.gz: 0515b3f19b46cdd5725ff1650ea4d87b7c354a16e535ccafe7282488558f4de09a159ee560c1f1ed2fa79f25938f4adcb266616ae31609359d78d7a5ea44c9d2
6
+ metadata.gz: e86abeee60243641fe003a20024e7a54bb756ce7decc1f43e4288f1fb0fc120821c87371d4423f3161e94e3e7f7e156d8a7abb58be343da11ddd250f5074b341
7
+ data.tar.gz: 24876ea56317cd8ab71d106cc58fc868d185307d4e4b4ff37299de00a33dc167f869909ed0b29523cd449a9e3c1e887a4cf3c9c761488c212b8227f53187f839
data/Contributing.md ADDED
@@ -0,0 +1,66 @@
1
+ ## Contributing
2
+
3
+ We value any contribution to cartage-rack you can provide: a bug report, a
4
+ feature request, or code contributions. cartage-rack is reasonably complex
5
+ code, so there are a few contribution guidelines:
6
+
7
+ * Changes *will* *not* be accepted without tests. The test suite is written
8
+ with [Minitest][].
9
+ * Match our coding style.
10
+ * Use a thoughtfully-named topic branch that contains your change. Rebase
11
+ your commits into logical chunks as necessary.
12
+ * Use [quality commit messages][].
13
+ * Do not change the version number; when your patch is accepted and a release
14
+ is made, the version will be updated at that point.
15
+ * Submit a GitHub pull request with your changes.
16
+
17
+ ### Test Dependencies
18
+
19
+ cartage-rack uses Ryan Davis’s [Hoe][] to manage the release process, which
20
+ adds a number of rake tasks. You will mostly be interested in:
21
+
22
+ $ rake
23
+
24
+ which runs the tests the same way that:
25
+
26
+ $ rake test
27
+ $ rake travis
28
+
29
+ will do.
30
+
31
+ To assist with the installation of the development dependencies for
32
+ cartage-rack, I have provided the simplest possible Gemfile pointing to the
33
+ (generated) `cartage-rack.gemspec` file. This will permit you to do:
34
+
35
+ $ bundle install
36
+
37
+ to get the development dependencies. If you aleady have `hoe` installed, you
38
+ can accomplish the same thing with:
39
+
40
+ $ rake newb
41
+
42
+ This task will install any missing dependencies, run the tests/specs, and
43
+ generate the RDoc.
44
+
45
+ ### Workflow
46
+
47
+ Here's the most direct way to get your work merged into the project:
48
+
49
+ * Fork the project.
50
+ * Clone down your fork (`git clone git://github.com/KineticCafe/cartage-rack.git`).
51
+ * Create a topic branch to contain your change (`git checkout -b my_awesome_feature`).
52
+ * Hack away, add tests. Not necessarily in that order.
53
+ * Make sure everything still passes by running `rake`.
54
+ * If necessary, rebase your commits into logical chunks, without errors.
55
+ * Push the branch up (`git push origin my_awesome_feature`).
56
+ * Create a pull request against KineticCafe/cartage-rack and describe
57
+ what your change does and the why you think it should be merged.
58
+
59
+ ### Contributors
60
+
61
+ * Austin Ziegler created cartage-rack.
62
+
63
+ [Minitest]: https://github.com/seattlerb/minitest
64
+ [quality commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
65
+ [Hoe]: https://github.com/seattlerb/hoe
66
+ [kccoc]: https://github.com/KineticCafe/code-of-conduct
data/History.md ADDED
@@ -0,0 +1,46 @@
1
+ ### 2.0 / 2016-05-DD
2
+
3
+ * Rewrote for compatibility with cartage 2.0.
4
+
5
+ * Renamed Cartage::Rack to Cartage::Rack::Simple and created a *new*
6
+ Cartage::Rack that returns more information.
7
+
8
+ * Extracted metadata gathering out of Cartage::Rack and into
9
+ Cartage::Rack::Metadata.
10
+
11
+ * Deprecated Cartage::Rack.mount in favour of Cartage::Rack() and
12
+ Cartage::Rack::Simple() methods.
13
+
14
+ * 1 governance change
15
+
16
+ * cartage-rack is now under the Kinetic Cafe Open Source [Code of
17
+ Conduct][kccoc].
18
+
19
+ ### 1.1 / 2015-04-11
20
+
21
+ * 2 minor enhancements
22
+
23
+ * Implemented Cartage::Rack#inspect to prevent `rake routes` from
24
+ presenting badly.
25
+
26
+ * Preparing for a future Cartage change to the contents of the
27
+ `release_hashref` file. The future `release_hashref` will be two lines:
28
+
29
+ hashref
30
+ timestamp
31
+
32
+ If `release_hashref` has two lines, the timestamp will be included in
33
+ the response. A timestamp will not be included if there is no
34
+ `release_hashref` file.
35
+
36
+ * 1 development change
37
+
38
+ * Implemented tests for Cartage::Rack.
39
+
40
+ ### 1.0 / 2015-03-20
41
+
42
+ * 1 major enhancement
43
+
44
+ * Birthday!
45
+
46
+ [kccoc]: https://github.com/KineticCafe/code-of-conduct
@@ -1,8 +1,8 @@
1
- == Licence
1
+ ## Licence
2
2
 
3
3
  This software is available under an MIT-style licence.
4
4
 
5
- * Copyright 2015 Kinetic Cafe
5
+ * Copyright 2015–2016 Kinetic Cafe
6
6
 
7
7
  Permission is hereby granted, free of charge, to any person obtaining a copy of
8
8
  this software and associated documentation files (the "Software"), to deal in
@@ -11,9 +11,9 @@ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11
11
  of the Software, and to permit persons to whom the Software is furnished to do
12
12
  so, subject to the following conditions:
13
13
 
14
- * The names of its contributors may not be used to endorse or promote
15
- products derived from this software without specific prior written
16
- permission.
14
+ * The names of its contributors may not be used to endorse or promote
15
+ products derived from this software without specific prior written
16
+ permission.
17
17
 
18
18
  The above copyright notice and this permission notice shall be included in all
19
19
  copies or substantial portions of the Software.
data/Manifest.txt CHANGED
@@ -1,14 +1,13 @@
1
- .autotest
2
- .gemtest
3
- .minitest.rb
4
- .travis.yml
5
- Contributing.rdoc
6
- Gemfile
7
- History.rdoc
8
- Licence.rdoc
1
+ Contributing.md
2
+ History.md
3
+ Licence.md
9
4
  Manifest.txt
10
5
  README.rdoc
11
6
  Rakefile
12
7
  lib/cartage/rack.rb
8
+ lib/cartage/rack/metadata.rb
9
+ lib/cartage/rack/simple.rb
13
10
  test/minitest_config.rb
14
11
  test/test_cartage_rack.rb
12
+ test/test_cartage_rack_metadata.rb
13
+ test/test_cartage_rack_simple.rb
data/README.rdoc CHANGED
@@ -7,7 +7,7 @@ continuous integration :: {<img src="https://travis-ci.org/KineticCafe/cartage-r
7
7
  == Description
8
8
 
9
9
  cartage-rack is a plug-in for {cartage}[https://github.com/KineticCafe/cartage]
10
- to provide a Rack application.
10
+ to provide a Rack application that reports on release metadata.
11
11
 
12
12
  Cartage provides a repeatable means to create a package for a Rails application
13
13
  that can be used in deployment with a configuration tool like Ansible, Chef,
@@ -17,58 +17,123 @@ control rules and without requiring development tool access.
17
17
 
18
18
  == Synopsis
19
19
 
20
- Cartage::Rack provides a Rack application generator to read and return the
21
- +release_hashref+ from an endpoint to verify that the server was deployed. This
22
- endpoint supports both JSON and plaintext output. To add this to a Rails
23
- application, simply mount it in +config/routes.rb+:
20
+ cartage-rack provides a generator method that instantiates a Rack application
21
+ that reports on release metadata, which will assist in verifying application
22
+ deploys.
23
+
24
+ To add the default generator to a Rails application, simply mount it in
25
+ +config/routes.rb+:
24
26
 
25
27
  require 'cartage/rack'
26
28
 
27
29
  Rails.application.routes.draw do
28
- get '/release' => Cartage::Rack.mount(Rails.root)
30
+ get '/release' => Cartage::Rack::Simple(Rails.root)
29
31
  end
30
32
 
31
- Or map it in a normal Rack application in +config.ru+:
33
+ To map it in a normal Rack application in +config.ru+:
32
34
 
33
35
  require 'cartage/rack'
34
36
  map('/release') do
35
- run Cartage::Rack.mount(Dir.pwd)
37
+ run Cartage::Rack::Simple(Dir.pwd)
36
38
  end
37
39
 
38
- It can then be queried easily:
40
+ Once mounted, it can then be queried easily:
39
41
 
40
42
  % rails start
41
43
  % curl localhost:3000/release
42
44
  development: (git) main
43
- % curl localhost:3000/release.json | jshon
45
+ % curl localhost:3000/release.json | jq .
44
46
  {
45
47
  "env" : "development",
46
48
  "release_hashref" : "(git) main"
47
49
  }
48
50
 
49
- If there is a +release_hashref+ file, the value returned will be from this
50
- file. There are two versions of +release_hashref+ files supported; the original
51
- format (Cartage 1.0 and 1.1) has one line (just the hashref of the release).
52
- The new format has two lines, the hashref of the release and the timestamp of
53
- the release.
51
+ == \Metadata
52
+
53
+ The core of cartage-rack is Cartage::Rack::Metadata, which collects data from
54
+ <tt>release-metadata.json</tt>, +release_hashref+, or the runtime environment
55
+ (if Cartage::Rack.require_metadata is +false+). You may instantiate the class
56
+ yourself if you wish to have a different sort of report for the release.
57
+
58
+ == \Metadata Reporters
59
+
60
+ There are two \Rack applications provided in cartage-rack 2.0 to report on
61
+ release metadata. \Metadata is pulled from <tt>release-metadata.json</tt>,
62
+ +release_hashref+, or the current environment (which allows Cartage::Rack
63
+ verification in development).
64
+
65
+ When reading +release_hashref+, the first line is the hashref of the release; a
66
+ second line, if present, is the Cartage timestamp of the release (an integer
67
+ value of the form +YYYYmmddHHMMSS+).
68
+
69
+ If a metadata file (<tt>release-metadata.json</tt> or <tt>release_hashref</tt>)
70
+ exists, it will be read on application creation and cached for the lifetime of
71
+ the Rack application. cartage-rack may be configured to throw an exception if a
72
+ metadata file cannot be found:
73
+
74
+ Cartage::Rack.require_metadata false
75
+
76
+ All reporters support JSON and plain text formats.
77
+
78
+ === Cartage::Rack
79
+
80
+ A full metadata reporter. This reporter may include information that is
81
+ considered *private* (including the source repository URL), so it is only
82
+ recommended for use on protected endpoints. The default report format is JSON.
83
+
84
+ The data returned is what is recorded in <tt>release-metadata.json</tt>, plus
85
+ the name of the environment.
54
86
 
55
- % curl localhost:3000/release.json | jshon
56
87
  {
57
- "env" : "production",
58
- "release_hashref" : "134458c3e3c02dd7c1cac8d5d41d85ce1e4decab"
59
- "timestamp" : "20150411001143"
88
+ "env": {
89
+ "name": "production",
90
+ },
91
+ "package": {
92
+ "name": "package-name",
93
+ "repo": {
94
+ "type": "git",
95
+ "url": "git:git@github.com/KineticCafe/cartage-rack.git"
96
+ },
97
+ hashref: "decafbad",
98
+ timestamp: "19851027024200"
99
+ }
60
100
  }
61
101
 
102
+ Mount this reporter with <tt>Cartage::Rack(Rails.root)</tt>. The data may be
103
+ filtered out by providing a block to <tt>Cartage::Rack()</tt> which modifies
104
+ the +metadata+ in place.
105
+
106
+ Cartage::Rack(Rails.root) do |metadata|
107
+ unless Rails.env.development?
108
+ # Remove the repo data before returning
109
+ metadata[:package].delete(:repo)
110
+ end
111
+ end
112
+
113
+ === Cartage::Rack::Simple
114
+
115
+ A simplified metadata reporter, including only the information that was
116
+ provided in cartage-rack 1.x (the environment, the hashref, and optionally a
117
+ timestamp). The default report format is plain text.
118
+
119
+ Mount this reporter with <tt>Cartage::Rack::Simple(Rails.root)</tt>. For
120
+ backwards compatibility, this reporter may also be mounted with
121
+ <tt>Cartage::Rack.mount(Rails.root)</tt>. The Simple reporter does not support
122
+ filtering.
123
+
62
124
  == Install
63
125
 
64
126
  Add cartage-rack to your Gemfile:
65
127
 
66
- gem 'cartage-rack', '~> 1.1'
128
+ gem 'cartage-rack', '~> 2.0'
67
129
 
68
130
  Or manually install:
69
131
 
70
132
  % gem install cartage-rack
71
133
 
134
+ cartage-rack should be in the main section of your Gemfile, unlike Cartage
135
+ itself.
136
+
72
137
  == cartage-rack Semantic Versioning
73
138
 
74
139
  cartage-rack uses a {Semantic Versioning}[http://semver.org/] scheme with one
@@ -79,6 +144,10 @@ change:
79
144
  cartage-rack will generally track cartage for major versions to ensure plugin API
80
145
  compatibility.
81
146
 
82
- :include: Contributing.rdoc
147
+ == Community and Contributing
83
148
 
84
- :include: Licence.rdoc
149
+ cartage-rack welcomes your contributions as described in
150
+ {Contributing.md}[https://github.com/KineticCafe/cartage-rack/blob/master/Contributing.md].
151
+ This project, like all Kinetic Cafe {open source
152
+ projects}[https://github.com/KineticCafe], is under the Kinetic Cafe Open
153
+ Source {Code of Conduct}[https://github.com/KineticCafe/code-of-conduct].
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
- # -*- ruby -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require 'pathname'
5
+ require 'rake/clean'
6
6
 
7
7
  Hoe.plugin :doofus
8
- Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
8
+ Hoe.plugin :email unless ENV['CI'] || ENV['TRAVIS']
9
9
  Hoe.plugin :gemspec2
10
10
  Hoe.plugin :git
11
11
  Hoe.plugin :minitest
@@ -15,46 +15,55 @@ Hoe.plugin :travis
15
15
  spec = Hoe.spec 'cartage-rack' do
16
16
  developer('Austin Ziegler', 'aziegler@kineticcafe.com')
17
17
 
18
- self.history_file = 'History.rdoc'
18
+ self.history_file = 'History.md'
19
19
  self.readme_file = 'README.rdoc'
20
- self.extra_rdoc_files = FileList['*.rdoc'].to_a
21
20
 
22
21
  license 'MIT'
23
22
 
24
- self.extra_dev_deps << ['rake', '~> 10.0']
25
- self.extra_dev_deps << ['rack-test', '~> 0.6']
26
- self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
27
- self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
28
- self.extra_dev_deps << ['hoe-git', '~> 1.5']
29
- self.extra_dev_deps << ['hoe-travis', '~> 1.2']
30
- self.extra_dev_deps << ['minitest', '~> 5.4']
31
- self.extra_dev_deps << ['minitest-autotest', '~> 1.0']
32
- self.extra_dev_deps << ['minitest-bisect', '~> 1.2']
33
- self.extra_dev_deps << ['minitest-focus', '~> 1.1']
34
- self.extra_dev_deps << ['minitest-moar', '~> 0.0']
35
- self.extra_dev_deps << ['minitest-pretty_diff', '~> 0.1']
36
- self.extra_dev_deps << ['simplecov', '~> 0.7']
23
+ ruby20!
24
+
25
+ # This gem *explicitly* does not have a hard link to cartage.
26
+
27
+ extra_dev_deps << ['rake', '>= 10.0']
28
+ extra_dev_deps << ['rdoc', '~> 4.2']
29
+ extra_dev_deps << ['rack-test', '~> 0.6']
30
+ extra_dev_deps << ['hoe-doofus', '~> 1.0']
31
+ extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
32
+ extra_dev_deps << ['hoe-git', '~> 1.5']
33
+ extra_dev_deps << ['hoe-travis', '~> 1.2']
34
+ extra_dev_deps << ['minitest', '~> 5.4']
35
+ extra_dev_deps << ['minitest-autotest', '~> 1.0']
36
+ extra_dev_deps << ['minitest-bisect', '~> 1.2']
37
+ extra_dev_deps << ['minitest-bonus-assertions', '~> 2.0']
38
+ extra_dev_deps << ['minitest-focus', '~> 1.1']
39
+ extra_dev_deps << ['minitest-hooks', '~> 1.4']
40
+ extra_dev_deps << ['minitest-moar', '~> 0.0']
41
+ extra_dev_deps << ['minitest-pretty_diff', '~> 0.1']
42
+ extra_dev_deps << ['timecop', '~> 0.8']
43
+ extra_dev_deps << ['simplecov', '~> 0.7']
37
44
  end
38
45
 
39
- module Hoe::Publish
40
- alias_method :original_make_rdoc_cmd, :make_rdoc_cmd
46
+ ENV['RUBYOPT'] = '-W0'
47
+
48
+ module Hoe::Publish #:nodoc:
49
+ alias __make_rdoc_cmd__cartage__ make_rdoc_cmd
41
50
 
42
51
  def make_rdoc_cmd(*extra_args) # :nodoc:
43
- spec.extra_rdoc_files.reject! { |f| f == 'Manifest.txt' }
44
- original_make_rdoc_cmd(*extra_args)
52
+ spec.extra_rdoc_files.delete_if { |f| f == 'Manifest.txt' }
53
+ __make_rdoc_cmd__cartage__(*extra_args)
45
54
  end
46
55
  end
47
56
 
48
57
  namespace :test do
49
- task :coverage do
50
- prelude = <<-EOS
51
- require 'simplecov'
52
- SimpleCov.start('test_frameworks') { command_name 'Minitest' }
53
- gem 'minitest'
54
- EOS
55
- spec.test_prelude = prelude.split($/).join('; ')
56
- Rake::Task['test'].execute
58
+ if File.exist?('.simplecov-prelude.rb')
59
+ task :coverage do
60
+ spec.test_prelude = 'load ".simplecov-prelude.rb"'
61
+
62
+ Rake::Task['test'].execute
63
+ end
57
64
  end
65
+
66
+ CLOBBER << 'coverage'
58
67
  end
59
68
 
60
- # vim: syntax=ruby
69
+ CLOBBER << 'tmp'
data/lib/cartage/rack.rb CHANGED
@@ -1,76 +1,105 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'json'
3
5
 
4
6
  # Cartage, a package builder.
5
- class Cartage; end
6
-
7
- # Cartage::Rack is a simple application that reads an application’s
8
- # +release_hashref+ and returns it as a +text/plain+ string, or as
9
- # +application/json+ if it is called with +.json+.
10
- #
11
- # If +release_hashref+ does not exist, Cartage::Rack will read the hash of the
12
- # current HEAD.
13
- class Cartage::Rack
14
- VERSION = '1.1' #:nodoc:
15
-
16
- # Creates a new version of the Cartage::Rack application to the specified
17
- # +root_path+, or +Dir.pwd+.
18
- def self.mount(root_path = nil)
19
- new(root_path || Dir.pwd)
7
+ class Cartage
8
+ # Generate and mount the full metadata reporter, Cartage::Rack.
9
+ def self.Rack(root_path = nil, &filter)
10
+ Cartage::Rack.send(:new, root_path, &filter)
20
11
  end
21
12
 
22
- # Sets the root path for Cartage::Rack.
23
- def initialize(root_path)
24
- @root_path = Pathname(root_path)
25
- end
13
+ # Cartage::Rack is a simple application that reads an application's static
14
+ # release metadata and returns it as an (optionally filtered)
15
+ # +application/json+ value, or as a +text/plain+ string if called with
16
+ # +.text+ or +.txt+.
17
+ class Rack
18
+ VERSION = '2.0.rc1' #:nodoc:
19
+
20
+ class << self
21
+ # When +true+, Cartage::Rack and Cartage::Rack::Simple will raise an
22
+ # exception if there is no metadata file (<tt>release-metadata.json</tt> or
23
+ # +release_hashref+). May be explicitly turned off.
24
+ #
25
+ # Defaults to +true+ except in development or test environments (based on
26
+ # <tt>$RAILS_ENV</tt> and <tt>$RACK_ENV</tt>).
27
+ def require_metadata(value = (arg = false; nil)) # rubocop:disable Style/Semicolon
28
+ @require_metadata = value unless arg == false
29
+ @require_metadata || default_require_metadata
30
+ end
26
31
 
27
- # The Rack application method.
28
- def call(env)
29
- content = {
30
- env: application_env,
31
- release_hashref: release_hashref,
32
- timestamp: timestamp
33
- }.delete_if(&->(_, v) { v.nil? })
34
-
35
- case env['PATH_INFO']
36
- when /\.json\z/
37
- type = 'application/json'
38
- body = content.to_json
39
- else
40
- type = 'text/plain'
41
- body = "#{content[:env]}: #{content[:release_hashref]}"
42
- body += " (#{content[:timestamp]})" if content[:timestamp]
32
+ private
33
+
34
+ def default_require_metadata
35
+ (ENV['RAILS_ENV'] || ENV['RACK_ENV']).to_s !~ /\A(?:development|test)\z/i
36
+ end
43
37
  end
44
38
 
45
- [ '200', { 'Content-Type' => type }, [ body ] ]
46
- end
39
+ def initialize(root_path = nil, &filter) # :nodoc:
40
+ @metadata = Cartage::Rack::Metadata.new(root_path, filter: filter)
41
+ end
47
42
 
48
- def inspect
49
- %Q(#{self.class} for #{@root_path.expand_path.basename})
50
- end
43
+ def call(env) #:nodoc:
44
+ type, body = resolve_content(env)
45
+ [ '200', { 'Content-Type' => type }, [ body ] ]
46
+ end
51
47
 
52
- private
53
- def application_env
54
- ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'UNKNOWN'
55
- end
48
+ def inspect #:nodoc:
49
+ "#{self.class} for #{@metadata.inspect}"
50
+ end
56
51
 
57
- def release_hashref
58
- file = @root_path.join('release_hashref')
59
- if file.exist?
60
- file.read.split($/).first.chomp
61
- elsif @root_path.join('.git').directory?
62
- "(git) #{%x(git rev-parse --abbrev-ref HEAD).chomp}"
63
- else
64
- 'UNKNOWN - no release_hashref or .git directory'
52
+ private
53
+
54
+ def resolve_content(env)
55
+ content = @metadata.resolve
56
+
57
+ case env['PATH_INFO']
58
+ when /\.te?xt\z/
59
+ type = 'text/plain'
60
+ body = [
61
+ "name: #{dig(content, 'package', 'name')}",
62
+ "environment: #{dig(content, 'env', 'name')}",
63
+ "hashref: #{dig(content, 'package', 'hashref')}"
64
+ ]
65
+
66
+ value = dig(content, 'package', 'timestamp')
67
+ body << "timestamp: #{value}" if value
68
+
69
+ repo = dig(content, 'package', 'repo')
70
+ body << "#{repo['type']}: #{repo['url']}" if repo
71
+ body = body.join("\n")
72
+ else
73
+ type = 'application/json'
74
+ body = content.to_json
75
+ end
76
+
77
+ [ type, body ]
65
78
  end
66
- end
67
79
 
68
- def timestamp
69
- file = @root_path.join('release_hashref')
70
- if file.exist?
71
- stamp = file.read.split($/, 2)[1]
72
- stamp = nil if stamp && stamp.empty?
73
- stamp.chomp if stamp
80
+ attr_reader :metadata
81
+
82
+ #:nocov:
83
+ def dig(hash, key, *rest)
84
+ if hash.respond_to?(:dig)
85
+ hash.dig(key, *rest)
86
+ else
87
+ DIGGER.call(hash, key, *rest)
88
+ end
74
89
  end
90
+
91
+ DIGGER = ->(h, k, *r) { #:nodoc:
92
+ v = h[k]
93
+ if v.nil? || r.empty?
94
+ v
95
+ else
96
+ DIGGER.call(v, *r)
97
+ end
98
+ }
99
+ private_constant :DIGGER
100
+ #:nocov:
75
101
  end
76
102
  end
103
+
104
+ require_relative 'rack/simple'
105
+ require_relative 'rack/metadata'