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 +4 -4
- data/.gitignore +2 -0
- data/Gemfile +1 -1
- data/README.org +206 -182
- data/lib/revision/cli.rb +16 -0
- data/lib/revision/md5.rb +51 -0
- data/lib/revision/releasable.rb +83 -40
- data/lib/revision/version.rb +16 -1
- data/releasables.yaml +11 -0
- data/revision.gemspec +17 -14
- metadata +104 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d15b43ba3833b4581b97b89a7c5ba40890373b5cc85f1186f5917e9ad5d5fb21
|
4
|
+
data.tar.gz: badf688375adaab009a16f4e03a250cb77725fcc3d140d3b47a38d7e8436a575
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33dea1ba91f478dc674d9c5b3f23f875b9ca192f9a3efa2a27f2e0e33b39a119ffb367353dd17e7b3ecb4ce17df64747b0edef415ea66eb9a1fe8604fae73378
|
7
|
+
data.tar.gz: 7c386e43dd4f3979462f0e0d4c1ca6ae29409f042d5239f5b1434ba7bb8ef4836d5ca70b0786bf86e0b83a4102191f60f4f23df883341c67a0fcd2b851f4d5d7
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
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
|
-
|
41
|
+
Ruby / Rubygems installed
|
43
42
|
|
44
43
|
** From rubygems.org
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
#+BEGIN_SRC sh
|
46
|
+
gem install revision
|
47
|
+
#+END_SRC
|
49
48
|
|
50
49
|
** From source
|
51
50
|
|
52
|
-
|
53
|
-
git clone git@
|
54
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
139
|
+
#+BEGIN_SRC sh
|
140
|
+
revision minor --id=firmware
|
141
|
+
#+END_SRC
|
138
142
|
|
139
143
|
** Configuration
|
140
144
|
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
146
|
-
|
149
|
+
- http://docs.ansible.com/ansible/latest/YAMLSyntax.html
|
150
|
+
- http://www.yaml.org/start.html
|
147
151
|
|
148
152
|
*** Syntax
|
149
153
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
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
|
-
|
246
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
269
|
+
#+END_SRC
|
263
270
|
|
264
271
|
* Development
|
265
272
|
|
266
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/revision/md5.rb
ADDED
@@ -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
|
data/lib/revision/releasable.rb
CHANGED
@@ -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
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
-
|
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
|
-
|
213
|
-
|
214
|
-
|
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
|
-
|
230
|
-
|
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
|
234
|
-
destination = File.expand_path(destination)
|
261
|
+
raise Errors::NotSpecified.new(':deploy') if destinations.empty?
|
235
262
|
|
236
|
-
|
237
|
-
|
238
|
-
end
|
263
|
+
destinations.each do |d|
|
264
|
+
destination = File.expand_path(d[:dest])
|
239
265
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
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
|
data/lib/revision/version.rb
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
# Defines the revision ID for the revision gem
|
2
2
|
module Revision
|
3
|
-
VERSION = "1.
|
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.
|
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
|
-
|
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
|
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", "~>
|
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
|
+
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:
|
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
|
+
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
|
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: '
|
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: '
|
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
|
-
|
129
|
-
|
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.
|
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: []
|