revision 1.5.3 → 1.6.0

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
  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