revision 1.4.1 → 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: fdf646b4e8e2eb07bec9aab1ec7663998a5e3d6585f5b5be560d7b76383fa20b
4
- data.tar.gz: 47492a7855c38a50484e44b04e637258b1529e3fd6a437f3fc13e07c8ba83107
3
+ metadata.gz: d15b43ba3833b4581b97b89a7c5ba40890373b5cc85f1186f5917e9ad5d5fb21
4
+ data.tar.gz: badf688375adaab009a16f4e03a250cb77725fcc3d140d3b47a38d7e8436a575
5
5
  SHA512:
6
- metadata.gz: 950eee331752b94d3f2ef712f8f06883d104145169547314eded26556cd41b798be6af1bfdf9011b961751737175b317e19c729991f28b87ff3ed5f3163b8e45
7
- data.tar.gz: b25b45f4df9917a0c6064224a0e509ff002249524ce72ad43b5cf81d4d6bdadda07a8cb65e1eda6f075717b81a0b996631ac1ade59c0b031ebdf74c36e73233a
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/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- #git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ # git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in revision.gemspec
6
6
  gemspec
data/README.org CHANGED
@@ -1,6 +1,5 @@
1
1
  #+TITLE: Revision management gem
2
2
  #+AUTHOR: Cormac Cannon
3
- #+EMAIL: cormac.cannon@neuromoddevices.com
4
3
  #+LANGUAGE: en
5
4
 
6
5
  # Generic properties
@@ -24,250 +23,275 @@
24
23
  # or alternatively #+SETUPFILE: theme-readtheorg.setup
25
24
 
26
25
  * Overview
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
- 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
29
- probably better off using bundler for ruby projects). It supports per-project configuration using a yaml-format file called =releasables.yaml= located at
30
- the project root.
28
+ It currently supports the following functionality
29
+ - Manage 3-component revision IDs embedded natively in source file
30
+ - Embeds/updates/extracts changelog in source file header/footer comments
31
+ - Automatically prompts for a changelog entry each time a revision identifier is incremented
32
+ - Optionally commits and tags changes to a git repo after an update to the revision ID
33
+ - Builds and archives projects in zip format (including release notes and arbitrary release artefacts defined
34
+ - Deploys build artefacts to one or more defined (local or remote) filesystem locations
35
+ - Automatically generates md5sums when archiving or deploying build artefacts
31
36
 
32
- It currently supports the following functionality
33
- - Manage 3-component revision IDs embedded natively in source file
34
- - Embeds/updates/extracts changelog in source file header/footer comments
35
- - Automatically prompts for a changelog entry each time a revision identifier is incremented
36
- - Optionally commits and tags changes to a git repo after an update to the revision ID
37
- - Builds and archives projects in zip format (including release notes and arbitrary release artefacts defined
38
- - Deploys
37
+ Hacked on sporadically to allow me to tag, archive and deploy projects in multiple languages in a consistent fashion.
39
38
 
40
39
  * Installation
41
40
  ** Dependencies
42
- Ruby / Rubygems installed
41
+ Ruby / Rubygems installed
43
42
 
44
43
  ** From rubygems.org
45
44
 
46
- #+BEGIN_SRC sh
47
- gem install revision
48
- #+END_SRC
45
+ #+BEGIN_SRC sh
46
+ gem install revision
47
+ #+END_SRC
49
48
 
50
49
  ** From source
51
50
 
52
- #+BEGIN_SRC sh
53
- git clone git@git.nmd.ie/lib/
54
- #+END_SRC
51
+ #+BEGIN_SRC sh
52
+ git clone git@github.com:cormacc/revision
53
+ #+END_SRC
55
54
 
56
55
 
57
56
  *** Checkout
58
57
 
59
- #+BEGIN_SRC sh
60
- gem install bundler
61
- git clone git@git.nmd.ie:gem/revision
62
- cd revision
63
- #+END_SRC
58
+ #+BEGIN_SRC sh
59
+ gem install bundler
60
+ git clone git@github.com:cormacc/revision
61
+ cd revision
62
+ #+END_SRC
64
63
 
65
64
  *** Install
66
65
 
67
- #+BEGIN_SRC sh
68
- bundle install
69
- bundle exec rake install
70
- #+END_SRC
71
-
72
- #+RESULTS:
73
- #+begin_example
74
- Using rake 10.5.0
75
- Using bundler 1.16.0
76
- Using coderay 1.1.2
77
- Using diff-lcs 1.3
78
- Using git 1.3.0
79
- Using method_source 0.9.0
80
- Using pry 0.11.3
81
- Using rubyzip 1.2.1
82
- Using thor 0.19.4
83
- Using revision 1.0.0 from source at `.`
84
- Using rspec-support 3.7.0
85
- Using rspec-core 3.7.0
86
- Using rspec-expectations 3.7.0
87
- Using rspec-mocks 3.7.0
88
- Using rspec 3.7.0
89
- Bundle complete! 5 Gemfile dependencies, 15 gems now installed.
90
- Use `bundle info [gemname]` to see where a bundled gem is installed.
91
- revision 1.0.0 built to pkg/revision-1.0.0.gem.
92
- revision (1.0.0) installed.
93
- #+end_example
66
+ #+BEGIN_SRC sh
67
+ bundle install
68
+ bundle exec rake install
69
+ #+END_SRC
70
+
71
+ #+RESULTS:
72
+ #+begin_example
73
+ Using rake 10.5.0
74
+ Using bundler 1.16.0
75
+ Using coderay 1.1.2
76
+ Using diff-lcs 1.3
77
+ Using git 1.3.0
78
+ Using method_source 0.9.0
79
+ Using pry 0.11.3
80
+ Using rubyzip 1.2.1
81
+ Using thor 0.19.4
82
+ Using revision 1.0.0 from source at `.`
83
+ Using rspec-support 3.7.0
84
+ Using rspec-core 3.7.0
85
+ Using rspec-expectations 3.7.0
86
+ Using rspec-mocks 3.7.0
87
+ Using rspec 3.7.0
88
+ Bundle complete! 5 Gemfile dependencies, 15 gems now installed.
89
+ Use `bundle info [gemname]` to see where a bundled gem is installed.
90
+ revision 1.0.0 built to pkg/revision-1.0.0.gem.
91
+ revision (1.0.0) installed.
92
+ #+end_example
94
93
 
95
94
  * Usage
96
95
 
97
96
  ** Supported Commands
98
- Run the executable with no arguments to get usage instructions in your console window...
99
-
100
- #+BEGIN_SRC sh
101
- revision
102
- #+END_SRC
103
-
104
- #+RESULTS:
105
- #+begin_example
106
- Loading releasable definitions from /home/cormacc/nextcloud/nmd/gem/revision/releasables.yaml ...
107
- Commands:
108
- revision archive # Archive releasables
109
- revision changelog # Display change log on stdout
110
- revision help [COMMAND] # Describe available commands or one specific command
111
- revision info # Display info for all defined releasables
112
- revision major # Increment major revision index
113
- revision minor # Increment minor revision index
114
- revision patch # Increment patch revision index
115
- revision tag # Commit the current revision to a local git repo ...
116
-
117
- Options:
118
- [--dryrun], [--no-dryrun]
119
- [--id=ID]
120
-
121
- #+end_example
122
-
123
- #+BEGIN_NOTE
124
- The tool can be run from any subfolder of a project root -- it will traverse the tree until it finds
125
- an ancestor containing =releasables.yaml= OR can go no further (in which case it throws an error).
126
- #+END_NOTE
97
+ Run the executable with no arguments to get usage instructions in your console window...
98
+
99
+ #+BEGIN_SRC sh
100
+ revision
101
+ #+END_SRC
102
+
103
+ #+RESULTS:
104
+ #+begin_example
105
+ Loading releasable definitions from /home/cormacc/nmd/gem/revision/releasables.yaml ...
106
+ Commands:
107
+ revision --version, -v # print the version
108
+ revision archive # Archive releasable(s)
109
+ revision build # Build releasable(s)
110
+ revision changelog # Display change log on stdout
111
+ revision deploy # Deploy releasable(s)
112
+ revision help [COMMAND] # Describe available commands or one specific command
113
+ revision info # Display info for all defined releasables
114
+ revision major # Increment major revision index
115
+ revision md5 # Compute md5sums for current build artefacts
116
+ revision minor # Increment minor revision index
117
+ revision package # Build and archive releasables
118
+ revision patch # Increment patch revision index
119
+ revision tag # Commit the current revision to a local git repo ...
120
+
121
+ Options:
122
+ [--dryrun], [--no-dryrun]
123
+ [--id=ID]
124
+
125
+ #+end_example
126
+
127
+ #+BEGIN_NOTE
128
+ The tool can be run from any subfolder of a project root -- it will traverse the tree until it finds
129
+ an ancestor containing =releasables.yaml= OR can go no further (in which case it throws an error).
130
+ #+END_NOTE
127
131
 
128
132
  *** Operating on multiple releasables
129
133
 
130
- A single =releasables.yaml= file can define multiple releasables, either implicitly (via inclusion) or explicitly
131
- (see [[Configuration]] section below for examples). In this context, the ~info~ and ~archive~ commands
132
- will operate on all defined releasables, whereas the remaining commands will require the releasable
133
- to be specified using the ~--id=~ option, e.g.
134
+ A single =releasables.yaml= file can define multiple releasables, either implicitly (via inclusion) or explicitly
135
+ (see [[Configuration]] section below for examples). In this context, the ~info~ and ~archive~ commands
136
+ will operate on all defined releasables, whereas the remaining commands will require the releasable
137
+ to be specified using the ~--id=~ option, e.g.
134
138
 
135
- #+BEGIN_SRC sh
136
- revision minor --id=firmware
137
- #+END_SRC
139
+ #+BEGIN_SRC sh
140
+ revision minor --id=firmware
141
+ #+END_SRC
138
142
 
139
143
  ** Configuration
140
144
 
141
- YAML syntax is used for the configuration file. The [[Syntax]] and [[Examples]] sections below should provide sufficient
142
- introduction to the limit subset of language features required to use this tool, however further info
143
- may be found at the following links:
145
+ YAML syntax is used for the configuration file. The [[Syntax]] and [[Examples]] sections below should provide sufficient
146
+ introduction to the limit subset of language features required to use this tool, however further info
147
+ may be found at the following links:
144
148
 
145
- - http://docs.ansible.com/ansible/latest/YAMLSyntax.html
146
- - http://www.yaml.org/start.html
149
+ - http://docs.ansible.com/ansible/latest/YAMLSyntax.html
150
+ - http://www.yaml.org/start.html
147
151
 
148
152
  *** Syntax
149
153
 
150
- The =releasables.yaml= file should contain a top level ~:releasables~ node.
151
- Under this, you can create a list (or YAML /sequence/) of releasable definitions.
152
-
153
- Each sequence item begins with a ~-~ and contains either a link to a folder containing its own =releasables.yaml=
154
- defining one or more releasables ...
155
-
156
- #+BEGIN_SRC yaml
157
- - :folder: relative/path/to/a/releasable/folder
158
- #+END_SRC
159
-
160
- ... or a single inline releasable definition.
161
-
162
- #+BEGIN_NOTE
163
- The lines beginning with '#' are explanatory comments
164
- #+END_NOTE
165
-
166
- #+BEGIN_SRC yaml
167
- - :id: my_releasable
168
- :revision:
169
- # Source file containing the revision identifier
170
- # This will also include changelog entries, embedded as comments
171
- :src: lib/revision/version.rb
172
- # Regex matching the source revision identifier. Must contain the following named capture groups
173
- # - major, minor, patch :: Numeric (uint) sequences representing the three revision ID components
174
- # - sep1, sep2 :: the characters separating the revision components
175
- # - prefix, postfix :: sufficient syntactic context to match the revision ID uniquely
176
- # N.B. this regex matches the version ID from the standard bundler gem skeleton,
177
- # e.g. VERSION = "1.1.0"
178
- :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
179
- # Comment char for the project language -- prefixed to each line of changelog entries
180
- # Quotes only necessary here to prevent # being interpreted as the beginning of a YAML comment
181
- :comment_prefix: "#"
182
- # Sequence of build steps -- each item should be a valid shell command, prefixed with the YAML sequence item token, '- '
183
- :build_steps:
184
- - bundle exec rake install
154
+ The =releasables.yaml= file should contain a top level ~:releasables~ node.
155
+ Under this, you can create a list (or YAML /sequence/) of releasable definitions.
156
+
157
+ Each sequence item begins with a ~-~ and contains either a link to a folder containing its own =releasables.yaml=
158
+ defining one or more releasables ...
159
+
160
+ #+BEGIN_SRC yaml
161
+ - :folder: relative/path/to/a/releasable/folder
162
+ #+END_SRC
163
+
164
+ ... or a single inline releasable definition.
165
+
166
+ #+BEGIN_NOTE
167
+ The lines beginning with '#' are explanatory comments
168
+ #+END_NOTE
169
+
170
+ #+BEGIN_SRC yaml
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
185
190
  # Sequence defining the files (build artefacts) to package in the release archive.
186
191
  # Each artefact definition must include a :src: key/value pair.
187
192
  # An optional :dest: value may be provided to rename the file during packaging, or just (as in the first entry below)
188
193
  # to flatten the folder structure.
189
194
  # Any <VER> (or <REV>) in the :src: or :dest: placeholders wil be replaced with the current revision ID
190
195
  # The revision archive will also include the revision history extracted as a text file
191
- :artefacts:
192
- # A binary artefact -- the
193
- - :src: pkg/revision-<VER>.gem
194
- :dest: revision-<VER>.gem
195
- # This document -- the :dest: value defaults to duplicating :src: if not specified
196
- - :src: README.org
197
- #+END_SRC
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
204
+ #+END_SRC
198
205
 
199
206
  **** TODO (or at least consider) add support for overridable defaults
200
- e.g. via a =.releasables= configuration file in the user home dir.
201
- Though this would be bad for collaborative development as the config file would live outside source control.
202
- Possibly useful to support inclusion of a controlled configuration file instead? Primarily to define
203
- a revision regex and comment prefix for a group of related releasables....
207
+ e.g. via a =.releasables= configuration file in the user home dir.
208
+ Though this would be bad for collaborative development as the config file would live outside source control.
209
+ Possibly useful to support inclusion of a controlled configuration file instead? Primarily to define
210
+ a revision regex and comment prefix for a group of related releasables....
204
211
 
205
212
  *** Examples
206
213
  **** C project
207
214
 
208
- #+BEGIN_NOTE
209
- The ~:regex:~ and ~:comment_prefix:~ keys are absent in the C example below. This project started life as
210
- managing some embedded C projects, and the default values reflect this.
211
- #+END_NOTE
212
-
213
- #+BEGIN_SRC yaml
214
- :releasables:
215
- - :id: mbt_cd_firmware
216
- :revision:
217
- :src: src/FirmwareRevision.c
218
- :build_steps:
219
- - make --jobs=8 -f Makefile CONF=bootloadable
220
- :artefacts:
221
- - :src: dist/bootloadable/production/firmware.production.hex
222
- :dest: mbt_cd_firmware_v<REV>.bootloadable.hex
223
- - :src: dist/default/production/firmware.production.hex
224
- :dest: mbt_cd_firmware_v<REV>.standalone.hex
225
- #+END_SRC
215
+ #+BEGIN_NOTE
216
+ The ~:regex:~ and ~:comment_prefix:~ keys are absent in the C example below. This project started life as
217
+ managing some embedded C projects, and the default values reflect this.
218
+ #+END_NOTE
219
+
220
+ #+BEGIN_SRC yaml
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
232
+ #+END_SRC
226
233
 
227
234
  **** Ruby project
228
235
 
229
- #+BEGIN_SRC yaml
230
- :releasables:
231
- - :id: revision
232
- :revision:
233
- :src: lib/revision/version.rb
234
- :regex: (?<prefix>VERSION = ")(?<major>\d+)(?<sep1>\.)(?<minor>\d+)(?<sep2>\.)(?<patch>\d+)(?<postfix>")
235
- :comment_prefix: "#"
236
- :build_steps:
237
- - bundle exec rake install
238
- :artefacts:
239
- - :src: pkg/revision-<VER>.gem
240
- #+END_SRC
236
+ #+BEGIN_SRC yaml
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
247
+ #+END_SRC
241
248
 
242
249
  *** Heirarchical project
243
- Rather than defining the releasable parameters inline, a =releasables.yaml= list entry can contain a (relative or absolute) link to another folder containing it's own =releasables.yaml=.
250
+ Rather than defining the releasable parameters inline, a =releasables.yaml= list entry can contain a (relative or absolute) link to another folder containing it's own =releasables.yaml=.
244
251
 
245
- i.e assuming the earlier examples were in folders =examples/c= and =examples/ruby= relative to a common root, a separate =releasables.yaml=
246
- at that root could include them as follows...
252
+ i.e assuming the earlier examples were in folders =examples/c= and =examples/ruby= relative to a common root, a separate =releasables.yaml=
253
+ at that root could include them as follows...
247
254
 
248
- #+BEGIN_SRC yaml
249
- :releasables:
250
- - :folder: examples/c
251
- - :folder: examples/ruby
252
- #+END_SRC
255
+ #+BEGIN_SRC yaml
256
+ :releasables:
257
+ - :folder: examples/c
258
+ - :folder: examples/ruby
259
+ #+END_SRC
253
260
 
254
261
  **** TODO consider supporting a higher-level aggregate revision ID
255
262
 
256
- #+BEGIN_SRC yaml
257
- :revision:
258
- :src: release_log.txt
263
+ #+BEGIN_SRC yaml
264
+ :revision:
265
+ :src: release_log.txt
259
266
  :releasables:
260
267
  - :folder: examples/c
261
268
  - :folder: examples/ruby
262
- #+END_SRC
269
+ #+END_SRC
263
270
 
264
271
  * Development
265
272
 
266
- After checking out the repo, run =bin/setup= to install dependencies. Then, run =rake spec= to run the tests. You can also run =bin/console= for an interactive prompt that will allow you to experiment.
273
+ ** Environment
274
+ After checking out the repo, run =bin/setup= to install dependencies. Then, run =rake spec= to run the tests. You can also run =bin/console= for an interactive prompt that will allow you to experiment.
275
+
276
+ ** Installation from source
277
+ To install this gem from source on your local machine, run =bundle exec rake install= from the repository root.
278
+
279
+ ** Incrementing release versions
280
+ You can do this using the gem, by entering one of the following commands at the repository root
281
+
282
+ | Command | Effect |
283
+ |------------------+----------------------------------------------|
284
+ | =revision patch= | Patch version increment, e.g. 1.1.0 -> 1.1.1 |
285
+ | =revision minor= | Patch version increment, e.g. 1.1.1 -> 1.2.0 |
286
+ | =revision major= | Major version increment, e.g. 1.2.0 -> 2.0.0 |
287
+
288
+ You'll be prompted to rebuild the gem, commit changes to the git repo and add a revision tag to the commit.
267
289
 
268
- To install this gem onto your local machine, run =bundle exec rake install=. To release a new version, update the version number in =version.rb=, and then run =bundle exec rake release=, which will create a git tag for the version, push git commits and tags, and push the =.gem= file to [rubygems.org](https://rubygems.org).
290
+ Alternatively, manually update the version number in =version.rb= and rebuild/install locally using =bundle exec rake install=
269
291
 
292
+ ** Deploying to rubygems
293
+ =bundle exec rake release=, will create a git tag for the version (if not, push git commits and tags, and push the =.gem= file to [rubygems.org](https://rubygems.org).
270
294
 
271
295
  * Contributing
272
296
 
273
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/revision.
297
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cormacc/revision.
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
 
@@ -95,7 +96,7 @@ module Revision
95
96
 
96
97
  def exec_pipeline(type, steps, skip_steps=0)
97
98
  exec_steps = steps[skip_steps..-1]
98
- puts "{type} :: Executing steps #{skip_steps+1} to #{steps.length}..."
99
+ puts "#{type} :: Executing steps #{skip_steps+1} to #{steps.length}..."
99
100
  Dir.chdir(@root) do
100
101
  exec_steps.each_with_index do |step, index|
101
102
  step_index = index+1+skip_steps
@@ -141,8 +142,12 @@ module Revision
141
142
  "#{@git_tag_prefix}#{revision}"
142
143
  end
143
144
 
145
+ def escape(a_string)
146
+ a_string.gsub('"',"\\\"")
147
+ end
148
+
144
149
  def tag_annotation
145
- @revision.last_changelog_entry.join("\n")
150
+ escape(@revision.last_changelog_entry.join("\n"))
146
151
  end
147
152
 
148
153
  def commit_message
@@ -153,7 +158,7 @@ module Revision
153
158
  commit_lines << "Also..."
154
159
  commit_lines += changelog_entry[2..-1]
155
160
  end
156
- commit_lines.join("\n")
161
+ escape(commit_lines.join("\n"))
157
162
  end
158
163
 
159
164
  def tag
@@ -183,72 +188,110 @@ module Revision
183
188
  "#{@id}_revision_history_v#{@revision}.txt"
184
189
  end
185
190
 
186
- def artefact_map(dest_prefix = '')
187
- amap = {}
188
- @artefacts.each_with_index do |a, index|
189
- src = a[:src].gsub(REVISION_PLACEHOLDER, @revision.to_s)
190
- dest = a[:dest].gsub(REVISION_PLACEHOLDER, @revision.to_s)
191
- if Gem.win_platform? && !src.end_with?('.exe') && File.exist?(File.join(@root, src + '.exe'))
192
- puts "... windows platform -- appending '.exe' (#{src})"
193
- src += '.exe'
194
- dest += '.exe' unless dest.end_with?('.exe')
195
- end
196
- src = File.join(@root,src)
197
- dest = dest_prefix.empty? ? dest : File.join(dest_prefix, dest)
198
- amap[src] = dest
199
- puts "... (#{index+1}/#{@artefacts.length}) #{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')
200
206
  end
201
- amap
207
+ a_norm
208
+ end
209
+
210
+ def artefacts
211
+ @artefacts.map { |a| normalise_artefact(a)}
202
212
  end
203
213
 
204
214
  def archive
205
215
  puts "Archiving #{@artefacts.length} build artefacts as #{archive_name}..."
206
- puts artefact_map
207
216
  if File.exist?(archive_name)
208
217
  puts "... deleting existing archive"
209
218
  File.delete(archive_name)
210
219
  end
211
220
  Zip::File.open(archive_name, Zip::File::CREATE) do |zipfile|
212
- artefact_map.each do |src, dest|
213
- #TODO: Add directory processing....
214
- 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
215
232
  end
216
233
  puts "... embedding revision history as #{changelog_name} "
217
234
  zipfile.get_output_stream(changelog_name) { |os| output_changelog(os)}
218
235
  end
236
+ archive_md5 = MD5.from_file(archive_name)
237
+ puts "... generating archive md5sum as #{archive_md5.md5filename} "
238
+ archive_md5.write
219
239
 
220
240
  if @config.dig(:archive)
221
241
  archive_root = File.expand_path(@config[:archive])
222
242
  puts "... moving #{archive_name} to #{archive_root}"
223
243
  FileUtils.mkdir_p(archive_root)
224
244
  FileUtils.mv(archive_name, archive_root)
245
+ FileUtils.mv(archive_md5.md5filename, archive_root)
225
246
  end
226
247
  end
227
248
 
228
249
  def deploy(destination='')
229
- if destination=='' and @config.dig(:deploy, :dest)
230
- destination = @config[:deploy][:dest]
250
+ destinations = []
251
+ if not destination.empty?
252
+ destinations.append({dest: destination})
253
+ elsif @config.dig(:deploy)
254
+ if @config[:deploy].kind_of?(Array)
255
+ destinations.append(*@config[:deploy])
256
+ else
257
+ destinations.append(@config[:deploy])
258
+ end
231
259
  end
232
260
 
233
- raise Errors::NotSpecified.new(':deploy/:dest') if destination==''
234
- destination = File.expand_path(destination)
261
+ raise Errors::NotSpecified.new(':deploy') if destinations.empty?
235
262
 
236
- if @config.dig(:deploy, :pre)
237
- exec_pipeline('deploy (pre)', @config[:deploy][:pre])
238
- end
263
+ destinations.each do |d|
264
+ destination = File.expand_path(d[:dest])
239
265
 
240
- puts "Deploying #{@artefacts.length} build artefacts to #{destination}..."
241
- artefact_map(destination).each do |src, dest|
242
- if File.exist?(dest)
243
- puts "... deleting existing '#{dest}'"
244
- FileUtils.rm_rf(dest)
266
+ if d.dig(:pre)
267
+ exec_pipeline('deploy (pre / #{d[:dest]})', d[:pre])
268
+ end
269
+
270
+ puts "Deploying #{artefacts.length} build artefacts to #{destination}..."
271
+ if not File.exist?(destination)
272
+ puts "... folder not found -> creating ... '#{destination}'"
273
+ FileUtils.mkdir_p(destination)
274
+ end
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}"
280
+ if File.exist?(dest)
281
+ puts "... deleting existing '#{dest}' ..."
282
+ FileUtils.rm_rf(dest)
283
+ end
284
+ puts "... deploying '#{src}' -> '#{dest}'"
285
+ FileUtils.cp_r(src,dest)
286
+ puts "... writing md5sum for '#{dest}' to '#{MD5.from_file(dest).write}'" if a[:md5]
287
+ end
288
+ File.open(File.join(destination,changelog_name),'w') { |f| output_changelog(f)}
289
+
290
+ if d.dig(:post)
291
+ exec_pipeline('deploy (post / #{d[:dest]})', d[:post])
245
292
  end
246
- FileUtils.cp_r(src,dest)
247
- end
248
- File.open(File.join(destination,changelog_name),'w') { |f| output_changelog(f)}
249
- if @config.dig(:deploy, :post)
250
- exec_pipeline('deploy (post)', @config[:deploy][:post])
251
293
  end
294
+
252
295
  end
253
296
 
254
297
  def package
@@ -1,10 +1,25 @@
1
1
  # Defines the revision ID for the revision gem
2
2
  module Revision
3
- VERSION = "1.4.1".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
+ #
11
+ # Version 1.5.3 (26 Oct 2021)
12
+ # - Multiple deployment destinations bugfix -- only last destination was being used.
13
+ #
14
+ # Version 1.5.2 (10 Jun 2020)
15
+ # - Uprevving around undeletable git tag
16
+ #
17
+ ## Version 1.5.1 (10 Jun 2020)
18
+ # - Escape " and ' in commit message when constructing git command line (' still problematic in some shells)
19
+ #
20
+ # Version 1.5.0 (13 Feb 2020)
21
+ # - Now handles multiple deployment destinations in releasables.yaml
22
+ #
8
23
  # Version 1.4.1 (18 Nov 2019)
9
24
  # - Updated to strip trailing whitespace after comment char for empty line
10
25
  #
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
data/revision.gemspec CHANGED
@@ -6,20 +6,12 @@ Gem::Specification.new do |spec|
6
6
  spec.name = "revision"
7
7
  spec.version = Revision::VERSION
8
8
  spec.authors = ["Cormac Cannon"]
9
- spec.email = ["cormac.cannon@neuromoddevices.com"]
9
+ spec.licenses = ['MIT']
10
10
 
11
11
  spec.summary = %q{Language-agnostic revision management tool}
12
12
  spec.description = %q{Updates project revision identifiers in software source files and associated change log. Can also build and package project archives as a zip and optionally commit, tag and push to a Git repo.}
13
- # spec.homepage = "TBC"
14
-
15
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
- # to allow pushing to a single host or delete this section to allow pushing to any host.
17
- # if spec.respond_to?(:metadata)
18
- # spec.metadata["allowed_push_host"] = "http://gems.nmd.ie"
19
- # else
20
- # raise "RubyGems 2.0 or newer is required to protect against " \
21
- # "public gem pushes."
22
- # end
13
+ spec.homepage = 'https://rubygems.org/gems/revision'
14
+ spec.metadata = { "source_code_uri" => "https://github.com/cormacc/revision" }
23
15
 
24
16
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
17
  f.match(%r{^(test|spec|features)/})
@@ -29,11 +21,22 @@ Gem::Specification.new do |spec|
29
21
 
30
22
  spec.require_paths = ["lib"]
31
23
 
32
- spec.add_runtime_dependency 'thor', '~> 0.19.1'
33
- spec.add_runtime_dependency 'rubyzip'
24
+ spec.add_runtime_dependency 'thor', '~> 1.0'
25
+ spec.add_runtime_dependency 'rubyzip', '~> 2.0'
34
26
 
35
27
  spec.add_development_dependency "bundler", "~> 2.0"
36
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 13.0"
37
29
  spec.add_development_dependency "rspec", "~> 3.0"
38
30
  spec.add_development_dependency "pry"
31
+ #emacs ruby layer deps...
32
+ #...lsp backend
33
+ spec.add_development_dependency "steep"
34
+ spec.add_development_dependency "solargraph"
35
+ #...robe backend
36
+ #....watch this space
37
+ #...generic
38
+ spec.add_development_dependency "ruby_parser"
39
+ spec.add_development_dependency "rubocop"
40
+ spec.add_development_dependency "prettier"
41
+ spec.add_development_dependency "seeing_is_believing"
39
42
  end
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.4.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cormac Cannon
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-18 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
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.19.1
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.19.1
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubyzip
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '2.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '13.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,11 +94,94 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: steep
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: solargraph
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: ruby_parser
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: prettier
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: seeing_is_believing
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
97
181
  description: Updates project revision identifiers in software source files and associated
98
182
  change log. Can also build and package project archives as a zip and optionally
99
183
  commit, tag and push to a Git repo.
100
184
  email:
101
- - cormac.cannon@neuromoddevices.com
102
185
  executables:
103
186
  - revision
104
187
  extensions: []
@@ -118,15 +201,18 @@ files:
118
201
  - lib/revision/cli.rb
119
202
  - lib/revision/errors.rb
120
203
  - lib/revision/info.rb
204
+ - lib/revision/md5.rb
121
205
  - lib/revision/releasable.rb
122
206
  - lib/revision/string_case.rb
123
207
  - lib/revision/version.rb
124
208
  - releasables.yaml
125
209
  - revision.gemspec
126
- homepage:
127
- licenses: []
128
- metadata: {}
129
- post_install_message:
210
+ homepage: https://rubygems.org/gems/revision
211
+ licenses:
212
+ - MIT
213
+ metadata:
214
+ source_code_uri: https://github.com/cormacc/revision
215
+ post_install_message:
130
216
  rdoc_options: []
131
217
  require_paths:
132
218
  - lib
@@ -141,8 +227,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
227
  - !ruby/object:Gem::Version
142
228
  version: '0'
143
229
  requirements: []
144
- rubygems_version: 3.0.6
145
- signing_key:
230
+ rubygems_version: 3.2.13
231
+ signing_key:
146
232
  specification_version: 4
147
233
  summary: Language-agnostic revision management tool
148
234
  test_files: []