revision 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aeac36b67440a0670c7b89fc3602ae9bfda2bc43add4f6ac3dbb44c0d2d7a45
4
- data.tar.gz: 4fa17d34cd367afafb0afb75343405a793ad2f732364ce36680059907d4b8f92
3
+ metadata.gz: d15b43ba3833b4581b97b89a7c5ba40890373b5cc85f1186f5917e9ad5d5fb21
4
+ data.tar.gz: badf688375adaab009a16f4e03a250cb77725fcc3d140d3b47a38d7e8436a575
5
5
  SHA512:
6
- metadata.gz: 231c4a899d91b78bc32e160b382b160df9a3e09f0953b81f16101b981bcb350d0252140e9cf075c5daeba75b91b968e54e2b7d382d3e3c949eb2d0fbcc1d01cd
7
- data.tar.gz: 6f63c22ed930a5a3830c89fe2902ff9ec6a9ebb01e79810bfa3690e28f25c3ae6e2f85a16d63c4c9a90a8ff6b681f1c937fd1082830381b4c9166de2f0368522
6
+ metadata.gz: 33dea1ba91f478dc674d9c5b3f23f875b9ca192f9a3efa2a27f2e0e33b39a119ffb367353dd17e7b3ecb4ce17df64747b0edef415ea66eb9a1fe8604fae73378
7
+ data.tar.gz: 7c386e43dd4f3979462f0e0d4c1ca6ae29409f042d5239f5b1434ba7bb8ef4836d5ca70b0786bf86e0b83a4102191f60f4f23df883341c67a0fcd2b851f4d5d7
data/.gitignore CHANGED
@@ -13,3 +13,5 @@ Gemfile.lock
13
13
 
14
14
  README.html
15
15
  *.zip
16
+ test-output
17
+ *.md5
data/README.org CHANGED
@@ -23,7 +23,7 @@
23
23
  # or alternatively #+SETUPFILE: theme-readtheorg.setup
24
24
 
25
25
  * Overview
26
- This gem automates revision management for source projects. The tool is language agnostic (used for C, ruby and matlab projects, to date -- though you're probably better off using bundler for ruby projects). It supports per-project configuration using a yaml-format file called =releasables.yaml= located at the project root.
26
+ This gem automates revision management for source projects. The tool is language agnostic (used for C, ruby, python and matlab projects, to date -- though you're probably better off using bundler for ruby projects). It supports per-project configuration using a yaml-format file called =releasables.yaml= located at the project root.
27
27
 
28
28
  It currently supports the following functionality
29
29
  - Manage 3-component revision IDs embedded natively in source file
@@ -31,9 +31,10 @@ It currently supports the following functionality
31
31
  - Automatically prompts for a changelog entry each time a revision identifier is incremented
32
32
  - Optionally commits and tags changes to a git repo after an update to the revision ID
33
33
  - Builds and archives projects in zip format (including release notes and arbitrary release artefacts defined
34
- - Deploys
34
+ - Deploys build artefacts to one or more defined (local or remote) filesystem locations
35
+ - Automatically generates md5sums when archiving or deploying build artefacts
35
36
 
36
- Worked on sporadically to allow me to tag, archive and deploy projects in multiple languages in a consistent fashion.
37
+ Hacked on sporadically to allow me to tag, archive and deploy projects in multiple languages in a consistent fashion.
37
38
 
38
39
  * Installation
39
40
  ** Dependencies
@@ -101,7 +102,7 @@ Run the executable with no arguments to get usage instructions in your console w
101
102
 
102
103
  #+RESULTS:
103
104
  #+begin_example
104
- Loading releasable definitions from /home/cormacc/dev/gem/revision/releasables.yaml ...
105
+ Loading releasable definitions from /home/cormacc/nmd/gem/revision/releasables.yaml ...
105
106
  Commands:
106
107
  revision --version, -v # print the version
107
108
  revision archive # Archive releasable(s)
@@ -111,6 +112,7 @@ Commands:
111
112
  revision help [COMMAND] # Describe available commands or one specific command
112
113
  revision info # Display info for all defined releasables
113
114
  revision major # Increment major revision index
115
+ revision md5 # Compute md5sums for current build artefacts
114
116
  revision minor # Increment minor revision index
115
117
  revision package # Build and archive releasables
116
118
  revision patch # Increment patch revision index
@@ -166,36 +168,39 @@ The lines beginning with '#' are explanatory comments
166
168
  #+END_NOTE
167
169
 
168
170
  #+BEGIN_SRC yaml
169
- - :id: my_releasable
170
- :revision:
171
- # Source file containing the revision identifier
172
- # This will also include changelog entries, embedded as comments
173
- :src: lib/revision/version.rb
174
- # Regex matching the source revision identifier. Must contain the following named capture groups
175
- # - major, minor, patch :: Numeric (uint) sequences representing the three revision ID components
176
- # - sep1, sep2 :: the characters separating the revision components
177
- # - prefix, postfix :: sufficient syntactic context to match the revision ID uniquely
178
- # N.B. this regex matches the version ID from the standard bundler gem skeleton,
179
- # e.g. VERSION = "1.1.0"
180
- :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
181
- # Comment char for the project language -- prefixed to each line of changelog entries
182
- # Quotes only necessary here to prevent # being interpreted as the beginning of a YAML comment
183
- :comment_prefix: "#"
184
- # Sequence of build steps -- each item should be a valid shell command, prefixed with the YAML sequence item token, '- '
185
- :build_steps:
186
- - bundle exec rake install
187
- # Sequence defining the files (build artefacts) to package in the release archive.
188
- # Each artefact definition must include a :src: key/value pair.
189
- # An optional :dest: value may be provided to rename the file during packaging, or just (as in the first entry below)
190
- # to flatten the folder structure.
191
- # Any <VER> (or <REV>) in the :src: or :dest: placeholders wil be replaced with the current revision ID
192
- # The revision archive will also include the revision history extracted as a text file
193
- :artefacts:
194
- # A binary artefact -- the
195
- - :src: pkg/revision-<VER>.gem
196
- :dest: revision-<VER>.gem
197
- # This document -- the :dest: value defaults to duplicating :src: if not specified
198
- - :src: README.org
171
+ :releasables
172
+ - :id: my_releasable
173
+ :revision:
174
+ # Source file containing the revision identifier
175
+ # This will also include changelog entries, embedded as comments
176
+ :src: lib/revision/version.rb
177
+ # Regex matching the source revision identifier. Must contain the following named capture groups
178
+ # - major, minor, patch :: Numeric (uint) sequences representing the three revision ID components
179
+ # - sep1, sep2 :: the characters separating the revision components
180
+ # - prefix, postfix :: sufficient syntactic context to match the revision ID uniquely
181
+ # N.B. this regex matches the version ID from the standard bundler gem skeleton,
182
+ # e.g. VERSION = "1.1.0"
183
+ :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
184
+ # Comment char for the project language -- prefixed to each line of changelog entries
185
+ # Quotes only necessary here to prevent # being interpreted as the beginning of a YAML comment
186
+ :comment_prefix: "#"
187
+ # Sequence of build steps -- each item should be a valid shell command, prefixed with the YAML sequence item token, '- '
188
+ :build_steps:
189
+ - bundle exec rake install
190
+ # Sequence defining the files (build artefacts) to package in the release archive.
191
+ # Each artefact definition must include a :src: key/value pair.
192
+ # An optional :dest: value may be provided to rename the file during packaging, or just (as in the first entry below)
193
+ # to flatten the folder structure.
194
+ # Any <VER> (or <REV>) in the :src: or :dest: placeholders wil be replaced with the current revision ID
195
+ # The revision archive will also include the revision history extracted as a text file
196
+ :artefacts:
197
+ # A binary artefact
198
+ - :src: pkg/revision-<VER>.gem
199
+ :dest: revision-<VER>.gem
200
+ # ':dest:' defaults to the string specified for ':src:' if not specified explicitly
201
+ # md5sums are generated by default for each artefact -- the ':md5:' option allows this to be disabled per-artefact
202
+ - :src: README.org
203
+ :md5: false
199
204
  #+END_SRC
200
205
 
201
206
  **** TODO (or at least consider) add support for overridable defaults
@@ -213,32 +218,32 @@ managing some embedded C projects, and the default values reflect this.
213
218
  #+END_NOTE
214
219
 
215
220
  #+BEGIN_SRC yaml
216
- :releasables:
217
- - :id: mbt_cd_firmware
218
- :revision:
219
- :src: src/FirmwareRevision.c
220
- :build_steps:
221
- - make --jobs=8 -f Makefile CONF=bootloadable
222
- :artefacts:
223
- - :src: dist/bootloadable/production/firmware.production.hex
224
- :dest: mbt_cd_firmware_v<REV>.bootloadable.hex
225
- - :src: dist/default/production/firmware.production.hex
226
- :dest: mbt_cd_firmware_v<REV>.standalone.hex
221
+ :releasables:
222
+ - :id: mbt_cd_firmware
223
+ :revision:
224
+ :src: src/FirmwareRevision.c
225
+ :build_steps:
226
+ - make --jobs=8 -f Makefile CONF=bootloadable
227
+ :artefacts:
228
+ - :src: dist/bootloadable/production/firmware.production.hex
229
+ :dest: mbt_cd_firmware_v<REV>.bootloadable.hex
230
+ - :src: dist/default/production/firmware.production.hex
231
+ :dest: mbt_cd_firmware_v<REV>.standalone.hex
227
232
  #+END_SRC
228
233
 
229
234
  **** Ruby project
230
235
 
231
236
  #+BEGIN_SRC yaml
232
- :releasables:
233
- - :id: revision
234
- :revision:
235
- :src: lib/revision/version.rb
236
- :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
237
- :comment_prefix: "#"
238
- :build_steps:
239
- - bundle exec rake install
240
- :artefacts:
241
- - :src: pkg/revision-<VER>.gem
237
+ :releasables:
238
+ - :id: revision
239
+ :revision:
240
+ :src: lib/revision/version.rb
241
+ :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
242
+ :comment_prefix: "#"
243
+ :build_steps:
244
+ - bundle exec rake install
245
+ :artefacts:
246
+ - :src: pkg/revision-<VER>.gem
242
247
  #+END_SRC
243
248
 
244
249
  *** Heirarchical project
@@ -250,7 +255,7 @@ at that root could include them as follows...
250
255
  #+BEGIN_SRC yaml
251
256
  :releasables:
252
257
  - :folder: examples/c
253
- - :folder: examples/ruby
258
+ - :folder: examples/ruby
254
259
  #+END_SRC
255
260
 
256
261
  **** TODO consider supporting a higher-level aggregate revision ID
@@ -260,7 +265,7 @@ at that root could include them as follows...
260
265
  :src: release_log.txt
261
266
  :releasables:
262
267
  - :folder: examples/c
263
- - :folder: examples/ruby
268
+ - :folder: examples/ruby
264
269
  #+END_SRC
265
270
 
266
271
  * Development
data/lib/revision/cli.rb CHANGED
@@ -4,6 +4,7 @@ require_relative 'releasable'
4
4
  require_relative 'info'
5
5
  require_relative 'errors'
6
6
  require_relative 'version'
7
+ require_relative 'md5'
7
8
 
8
9
  module Revision
9
10
  class CLI < Thor
@@ -105,6 +106,21 @@ module Revision
105
106
  select_one.tag
106
107
  end
107
108
 
109
+ desc 'md5', 'Compute md5sums for current build artefacts'
110
+ method_option :file, :aliases => "-f", :type => :string, :default => nil ,:desc => "File to md5sum (defaults to build artefacts defined in yaml)"
111
+ def md5
112
+ r = select_one
113
+ files = options[:file].nil? ?
114
+ r.artefacts.select { |a| a[:md5]==true }.map { |a| a[:src] } :
115
+ [options[:file]]
116
+ raise "No files specified" unless files.length
117
+ puts "Calculating md5sum for files #{files}"
118
+ for f in files
119
+ md5sum = Revision::MD5.from_file(f)
120
+ puts "#{md5sum}"
121
+ end
122
+ end
123
+
108
124
  private
109
125
 
110
126
  def id_options
@@ -0,0 +1,51 @@
1
+ require 'digest'
2
+
3
+ class Revision::MD5
4
+
5
+ READ_CHUNK_KB = 1024
6
+ FILENAME_EXTENSION = "md5"
7
+
8
+ attr_reader :root, :filename
9
+
10
+ def self.from_file(filepath, filename: nil)
11
+ raise "File #{filepath} not found" unless File.exist?(filepath)
12
+ filename ||= File.basename(filepath)
13
+ root = File.dirname(filepath)
14
+ stream = File.open(filepath, 'rb')
15
+ new(stream, filename, root: root)
16
+ end
17
+
18
+ def initialize(ioreader, filename, root: nil)
19
+ root ||= Dir.getwd
20
+ @reader = ioreader
21
+ @root = root
22
+ @filename = filename
23
+ end
24
+
25
+ def calc
26
+ md5 = Digest::MD5.new
27
+ bytes_per_chunk = READ_CHUNK_KB*1024
28
+ while chunk = @reader.read(bytes_per_chunk)
29
+ md5 << chunk
30
+ end
31
+ md5.hexdigest
32
+ end
33
+
34
+ def to_s
35
+ <<~EOT
36
+ #{calc} #{@filename}
37
+ EOT
38
+ end
39
+
40
+ def md5filename
41
+ "#{@filename}.#{FILENAME_EXTENSION}"
42
+ end
43
+
44
+ def write(filepath: nil)
45
+ filepath ||= File.join(@root, md5filename)
46
+ filename = File.basename(filepath)
47
+ File.open(filepath, "w") { |f| f.write "#{calc} #{filename}" }
48
+ filepath
49
+ end
50
+
51
+ end
@@ -68,7 +68,8 @@ module Revision
68
68
  # Legacy definition syntax compatibility
69
69
  @build_def = config[:build] ? config[:build] : { environment: { variables: {}}, steps: config[:build_steps]}
70
70
  @artefacts = config[:artefacts] || []
71
- @artefacts.each { |a| a[:dest] ||= a[:src] } unless @artefacts.nil? || @artefacts.empty?
71
+ @artefacts.each { |a| a[:dest] ||= File.basename(a[:src]) } unless @artefacts.nil? || @artefacts.empty?
72
+ # @artefacts.each { |a| a[:md5] = true if a[:md5].nil? } unless @artefacts.nil? || @artefacts.empty?
72
73
  @config = config
73
74
  end
74
75
 
@@ -187,46 +188,61 @@ module Revision
187
188
  "#{@id}_revision_history_v#{@revision}.txt"
188
189
  end
189
190
 
190
- def artefact_map(dest_prefix = '')
191
- amap = {}
192
- @artefacts.each_with_index do |a, index|
193
- src = a[:src].gsub(REVISION_PLACEHOLDER, @revision.to_s)
194
- dest = a[:dest].gsub(REVISION_PLACEHOLDER, @revision.to_s)
195
- if Gem.win_platform? && !src.end_with?('.exe') && File.exist?(File.join(@root, src + '.exe'))
196
- puts "... windows platform -- appending '.exe' (#{src})"
197
- src += '.exe'
198
- dest += '.exe' unless dest.end_with?('.exe')
199
- end
200
- src = File.join(@root,src)
201
- dest = dest_prefix.empty? ? dest : File.join(dest_prefix, dest)
202
- amap[src] = dest
191
+ def interp_rev(string)
192
+ string.gsub(REVISION_PLACEHOLDER, @revision.to_s)
193
+ end
194
+
195
+ def normalise_artefact(a)
196
+ src_norm = interp_rev(a[:src])
197
+ a_norm = {
198
+ src: src_norm,
199
+ dest: a[:dest].nil? ? File.basename(src_norm) : interp_rev(a[:dest]),
200
+ md5: a[:md5].nil? ? true : a[:md5]
201
+ }
202
+ if Gem.win_platform? && !a_norm[:src].end_with?('.exe') && File.exist?(File.join(@root, a_norm[:src] + '.exe'))
203
+ puts "... windows platform -- appending '.exe' ('#{a_norm[:src]}' -> '#{a_norm[src]}.exe')"
204
+ a_norm[:src] += '.exe'
205
+ a_norm[:dest] += '.exe' unless a_norm[:dest].end_with?('.exe')
203
206
  end
204
- amap
207
+ a_norm
208
+ end
209
+
210
+ def artefacts
211
+ @artefacts.map { |a| normalise_artefact(a)}
205
212
  end
206
213
 
207
214
  def archive
208
215
  puts "Archiving #{@artefacts.length} build artefacts as #{archive_name}..."
209
- amap = artefact_map
210
216
  if File.exist?(archive_name)
211
217
  puts "... deleting existing archive"
212
218
  File.delete(archive_name)
213
219
  end
214
220
  Zip::File.open(archive_name, Zip::File::CREATE) do |zipfile|
215
- amap.each.with_index(1) do |entry, idx|
216
- src, dest = entry
217
- #TODO: Add directory processing....
218
- puts "... (#{idx}/#{amap.length}) #{src} => #{dest}"
219
- zipfile.add(dest, src)
221
+ zip_entries = artefacts
222
+ zip_entries.each.with_index(1) do |a, idx|
223
+ puts "... (#{idx}/#{zip_entries.length}) #{a[:dest]} :: <= #{a[:src]}"
224
+ zipfile.add(a[:dest], a[:src])
225
+ if a[:md5]
226
+ md5name = "#{a[:dest]}.md5"
227
+ puts "... (#{idx}/#{zip_entries.length}) #{a[:dest]} :: embedding md5sum (#{md5name})"
228
+ zipfile.get_output_stream(md5name) { |os| os.write("#{MD5.from_file(a[:src])}")}
229
+ else
230
+ puts "... (#{idx}/#{zip_entries.length}) #{a[:dest]} :: no md5sum required"
231
+ end
220
232
  end
221
233
  puts "... embedding revision history as #{changelog_name} "
222
234
  zipfile.get_output_stream(changelog_name) { |os| output_changelog(os)}
223
235
  end
236
+ archive_md5 = MD5.from_file(archive_name)
237
+ puts "... generating archive md5sum as #{archive_md5.md5filename} "
238
+ archive_md5.write
224
239
 
225
240
  if @config.dig(:archive)
226
241
  archive_root = File.expand_path(@config[:archive])
227
242
  puts "... moving #{archive_name} to #{archive_root}"
228
243
  FileUtils.mkdir_p(archive_root)
229
244
  FileUtils.mv(archive_name, archive_root)
245
+ FileUtils.mv(archive_md5.md5filename, archive_root)
230
246
  end
231
247
  end
232
248
 
@@ -244,12 +260,6 @@ module Revision
244
260
 
245
261
  raise Errors::NotSpecified.new(':deploy') if destinations.empty?
246
262
 
247
- #... Eliminated global deployment pre/post functions.
248
- #... if applicable to all dests, the logic should probably be a build step...
249
- # if @config.dig(:deploy, :pre)
250
- # exec_pipeline('deploy (pre)', @config[:deploy][:pre])
251
- # end
252
-
253
263
  destinations.each do |d|
254
264
  destination = File.expand_path(d[:dest])
255
265
 
@@ -257,21 +267,23 @@ module Revision
257
267
  exec_pipeline('deploy (pre / #{d[:dest]})', d[:pre])
258
268
  end
259
269
 
260
- puts "Deploying #{@artefacts.length} build artefacts to #{destination}..."
270
+ puts "Deploying #{artefacts.length} build artefacts to #{destination}..."
261
271
  if not File.exist?(destination)
262
272
  puts "... folder not found -> creating ... '#{destination}'"
263
273
  FileUtils.mkdir_p(destination)
264
274
  end
265
- amap = artefact_map(destination)
266
- amap.each.with_index(1) do |entry, idx|
267
- src, dest = entry
268
- puts "... (#{idx}/#{amap.length}) #{src} => #{dest}"
275
+ artefacts.each.with_index(1) do |a, idx|
276
+ # src, dest = entry
277
+ src = File.join(@root,a[:src])
278
+ dest = destination.empty? ? a[:dest] : File.join(destination, a[:dest])
279
+ puts "... (#{idx}/#{artefacts.length}) #{src} => #{dest}"
269
280
  if File.exist?(dest)
270
281
  puts "... deleting existing '#{dest}' ..."
271
282
  FileUtils.rm_rf(dest)
272
283
  end
273
- puts "... deploying '#{src}' -> '#{dest}"
284
+ puts "... deploying '#{src}' -> '#{dest}'"
274
285
  FileUtils.cp_r(src,dest)
286
+ puts "... writing md5sum for '#{dest}' to '#{MD5.from_file(dest).write}'" if a[:md5]
275
287
  end
276
288
  File.open(File.join(destination,changelog_name),'w') { |f| output_changelog(f)}
277
289
 
@@ -280,9 +292,6 @@ module Revision
280
292
  end
281
293
  end
282
294
 
283
- # if @config.dig(:deploy, :post)
284
- # exec_pipeline('deploy (post)', @config[:deploy][:post])
285
- # end
286
295
  end
287
296
 
288
297
  def package
@@ -1,10 +1,13 @@
1
1
  # Defines the revision ID for the revision gem
2
2
  module Revision
3
- VERSION = "1.5.3".freeze
3
+ VERSION = "1.6.0".freeze
4
4
  end
5
5
 
6
6
  # <BEGIN CHANGELOG>
7
7
  #
8
+ # Version 1.6.0 (01 Dec 2021)
9
+ # - New feature: Automated MD5sum generation during 'archive' and 'deploy' tasks
10
+ #
8
11
  # Version 1.5.3 (26 Oct 2021)
9
12
  # - Multiple deployment destinations bugfix -- only last destination was being used.
10
13
  #
data/releasables.yaml CHANGED
@@ -5,6 +5,17 @@
5
5
  :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>".freeze)
6
6
  :comment_prefix: "#"
7
7
  :build_steps:
8
+ - mkdir -p test-output/2
8
9
  - bundle exec rake install
10
+ #Define 3 build artefacts as test cases for 'deploy' and 'archive' tasks
11
+ #Expect MD5 file to be generated by default for first entry (where not specified explicitly)
9
12
  :artefacts:
10
13
  - :src: pkg/revision-<VER>.gem
14
+ - :src: README.org
15
+ :md5: false
16
+ - :src: Rakefile
17
+ :md5: true
18
+ #Define two deployment destinations to verify multiple deployments work as intended
19
+ :deploy:
20
+ - :dest: ./test-output
21
+ - :dest: ./test-output/2
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: revision
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.3
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cormac Cannon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-26 00:00:00.000000000 Z
11
+ date: 2021-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -201,6 +201,7 @@ files:
201
201
  - lib/revision/cli.rb
202
202
  - lib/revision/errors.rb
203
203
  - lib/revision/info.rb
204
+ - lib/revision/md5.rb
204
205
  - lib/revision/releasable.rb
205
206
  - lib/revision/string_case.rb
206
207
  - lib/revision/version.rb