revision 1.4.1 → 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: 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: []