ndr_support 3.3.0 → 4.0.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/Guardfile +18 -10
- data/README.md +1 -22
- data/Rakefile +1 -1
- data/code_safety.yml +6 -10
- data/lib/ndr_support/version.rb +4 -2
- data/ndr_support.gemspec +2 -0
- metadata +36 -3
- data/lib/tasks/audit_code.rake +0 -475
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d551092d3ebfd8087efcbfa8321e1a7ead1837e3
|
4
|
+
data.tar.gz: 9b6649a2ddae13a5f9f0dacb73cdad200a62c51f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18b986bdcb86d9457514752dd6cbb7a4db9b52daa3814eebd312ef99078d3d2a649e9690f77055189ba89097bc6422c571bfdec94f3872d24c1a4876c1f6a49c
|
7
|
+
data.tar.gz: 8acdf5704f9e9b0cdc47fb1b0d31c2051d8eb3ed6a59e23c82ad9975c6d2305b8948443145df8c12e3045885dfcc0dc5e7cee2f3777e57b68a7e3c80046cacbd
|
data/Guardfile
CHANGED
@@ -1,16 +1,24 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
# This group allows to skip running rubocop when tests fail.
|
5
|
+
group :red_green_refactor, halt_on_fail: true do
|
6
|
+
guard :minitest do
|
7
|
+
watch(%r{^test/.+_test\.rb$})
|
8
|
+
watch('test/test_helper.rb') { 'test' }
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
# Non-rails
|
11
|
+
watch(%r{^lib/ndr_support/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
12
|
+
end
|
13
13
|
|
14
|
-
#
|
15
|
-
|
14
|
+
# automatically check Ruby code style with Rubocop when files are modified
|
15
|
+
guard :shell do
|
16
|
+
watch(/.+\.(rb|rake)$/) do |m|
|
17
|
+
unless system("bundle exec rake rubocop:diff #{m[0]}")
|
18
|
+
Notifier.notify "#{File.basename(m[0])} inspected, offenses detected",
|
19
|
+
title: 'RuboCop results (partial)', image: :failed
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
16
24
|
end
|
data/README.md
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
This is the Public Health England (PHE) National Disease Registers (NDR) Support ruby gem, providing:
|
4
4
|
|
5
5
|
1. core ruby class extensions;
|
6
|
-
2. additional time, regular expression, file security and encoding classes
|
7
|
-
3. rake tasks to manage code auditing of ruby based projects.
|
6
|
+
2. additional time, regular expression, file security and encoding classes.
|
8
7
|
|
9
8
|
## Installation
|
10
9
|
|
@@ -54,26 +53,6 @@ To enable this add the following line to your code:
|
|
54
53
|
include NdrSupport::YAML::SerializationMigration
|
55
54
|
```
|
56
55
|
|
57
|
-
### Code Auditing Rake Tasks
|
58
|
-
|
59
|
-
ndr_support also provides a mechanism to manage the state of routine code quality and security peer reviews. It should be used as part of wider quality and security policies.
|
60
|
-
|
61
|
-
It provides rake tasks to help manage the process of persisting the state of security reviews.
|
62
|
-
|
63
|
-
Once files have been reviewed as secure, the revision number for that file is stored in code_safety.yml. If used within a Rails app, this file is stored in the config/ folder, otherwise it is kept in the project's root folder.
|
64
|
-
|
65
|
-
Note: This feature works with svn and git repositories and svn, git-svn and git working copies.
|
66
|
-
|
67
|
-
To add code auditing to your project add this line to your application's Rakefile:
|
68
|
-
|
69
|
-
```ruby
|
70
|
-
require 'ndr_support/tasks'
|
71
|
-
```
|
72
|
-
|
73
|
-
For more details of the tasks available, execute:
|
74
|
-
|
75
|
-
$ rake -T audit
|
76
|
-
|
77
56
|
## Contributing
|
78
57
|
|
79
58
|
1. Fork it ( https://github.com/PublicHealthEngland/ndr_support/fork )
|
data/Rakefile
CHANGED
data/code_safety.yml
CHANGED
@@ -27,19 +27,19 @@ file safety:
|
|
27
27
|
Guardfile:
|
28
28
|
comments:
|
29
29
|
reviewed_by: timgentry
|
30
|
-
safe_revision:
|
30
|
+
safe_revision: e33e9dae7f38bc449ce9276515a539836dbbbd53
|
31
31
|
LICENSE.txt:
|
32
32
|
comments:
|
33
33
|
reviewed_by: timgentry
|
34
34
|
safe_revision: 90328cca8494539257e192a63b240a91c89f0616
|
35
35
|
README.md:
|
36
36
|
comments:
|
37
|
-
reviewed_by:
|
38
|
-
safe_revision:
|
37
|
+
reviewed_by: timgentry
|
38
|
+
safe_revision: e33e9dae7f38bc449ce9276515a539836dbbbd53
|
39
39
|
Rakefile:
|
40
40
|
comments:
|
41
41
|
reviewed_by: timgentry
|
42
|
-
safe_revision:
|
42
|
+
safe_revision: e33e9dae7f38bc449ce9276515a539836dbbbd53
|
43
43
|
gemfiles/Gemfile.rails32:
|
44
44
|
comments:
|
45
45
|
reviewed_by: pauleves
|
@@ -159,19 +159,15 @@ file safety:
|
|
159
159
|
lib/ndr_support/version.rb:
|
160
160
|
comments:
|
161
161
|
reviewed_by: timgentry
|
162
|
-
safe_revision:
|
162
|
+
safe_revision: 04c7617a6cc63d614e53cd6bc053dec46cc15786
|
163
163
|
lib/ndr_support/yaml/serialization_migration.rb:
|
164
164
|
comments:
|
165
165
|
reviewed_by: timgentry
|
166
166
|
safe_revision: 29595e6431587ff9b7db6e3ad3abbb3577bff99c
|
167
|
-
lib/tasks/audit_code.rake:
|
168
|
-
comments:
|
169
|
-
reviewed_by: josh.pencheon
|
170
|
-
safe_revision: 20cde082ee86a547de7b21a97a695bb307ac9f64
|
171
167
|
ndr_support.gemspec:
|
172
168
|
comments:
|
173
169
|
reviewed_by: timgentry
|
174
|
-
safe_revision:
|
170
|
+
safe_revision: e33e9dae7f38bc449ce9276515a539836dbbbd53
|
175
171
|
test/array_test.rb:
|
176
172
|
comments:
|
177
173
|
reviewed_by: timgentry
|
data/lib/ndr_support/version.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This defines the NdrSupport version. If you change it, rebuild and commit the gem.
|
2
|
-
# Use "rake build" to build the gem, see rake -T for all bundler rake tasks
|
4
|
+
# Use "rake build" to build the gem, see rake -T for all bundler rake tasks.
|
3
5
|
module NdrSupport
|
4
|
-
VERSION = '
|
6
|
+
VERSION = '4.0.0'
|
5
7
|
end
|
data/ndr_support.gemspec
CHANGED
@@ -31,8 +31,10 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'minitest', '>= 5.0.0'
|
32
32
|
spec.add_development_dependency 'mocha', '~> 1.1'
|
33
33
|
|
34
|
+
spec.add_development_dependency 'ndr_dev_support', '~> 1.1', '>= 1.1.1'
|
34
35
|
spec.add_development_dependency 'guard'
|
35
36
|
spec.add_development_dependency 'guard-rubocop'
|
37
|
+
spec.add_development_dependency 'guard-shell'
|
36
38
|
spec.add_development_dependency 'guard-minitest'
|
37
39
|
spec.add_development_dependency 'terminal-notifier-guard' if RUBY_PLATFORM =~ /darwin/
|
38
40
|
spec.add_development_dependency 'simplecov'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ndr_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NCRS Development Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -106,6 +106,26 @@ dependencies:
|
|
106
106
|
- - ~>
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '1.1'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: ndr_dev_support
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ~>
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '1.1'
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 1.1.1
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.1'
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 1.1.1
|
109
129
|
- !ruby/object:Gem::Dependency
|
110
130
|
name: guard
|
111
131
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +154,20 @@ dependencies:
|
|
134
154
|
- - '>='
|
135
155
|
- !ruby/object:Gem::Version
|
136
156
|
version: '0'
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
name: guard-shell
|
159
|
+
requirement: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
type: :development
|
165
|
+
prerelease: false
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - '>='
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
137
171
|
- !ruby/object:Gem::Dependency
|
138
172
|
name: guard-minitest
|
139
173
|
requirement: !ruby/object:Gem::Requirement
|
@@ -224,7 +258,6 @@ files:
|
|
224
258
|
- lib/ndr_support/utf8_encoding/object_support.rb
|
225
259
|
- lib/ndr_support/version.rb
|
226
260
|
- lib/ndr_support/yaml/serialization_migration.rb
|
227
|
-
- lib/tasks/audit_code.rake
|
228
261
|
- ndr_support.gemspec
|
229
262
|
- test/array_test.rb
|
230
263
|
- test/concerns/working_days_test.rb
|
data/lib/tasks/audit_code.rake
DELETED
@@ -1,475 +0,0 @@
|
|
1
|
-
SAFETY_FILE =
|
2
|
-
if File.exist?('code_safety.yml')
|
3
|
-
'code_safety.yml'
|
4
|
-
elsif defined?(Rails)
|
5
|
-
Rails.root.join('config', 'code_safety.yml')
|
6
|
-
else
|
7
|
-
'code_safety.yml'
|
8
|
-
end
|
9
|
-
|
10
|
-
# Temporary overrides to only audit external access files
|
11
|
-
SAFETY_REPOS = [['/svn/era', '/svn/extra/era/external-access']]
|
12
|
-
|
13
|
-
require 'yaml'
|
14
|
-
|
15
|
-
# Parameter max_print is number of entries to print before truncating output
|
16
|
-
# (negative value => print all)
|
17
|
-
def audit_code_safety(max_print = 20, ignore_new = false, show_diffs = false, show_in_priority = false, user_name = 'usr')
|
18
|
-
puts 'Running source code safety audit script.'
|
19
|
-
puts
|
20
|
-
|
21
|
-
max_print = 1_000_000 if max_print < 0
|
22
|
-
safety_cfg = File.exist?(SAFETY_FILE) ? YAML.load_file(SAFETY_FILE) : {}
|
23
|
-
file_safety = safety_cfg['file safety']
|
24
|
-
if file_safety.nil?
|
25
|
-
puts "Creating new 'file safety' block in #{SAFETY_FILE}"
|
26
|
-
safety_cfg['file safety'] = file_safety = {}
|
27
|
-
end
|
28
|
-
file_safety.each do |_k, v|
|
29
|
-
rev = v['safe_revision']
|
30
|
-
v['safe_revision'] = rev.to_s if rev.is_a?(Integer)
|
31
|
-
end
|
32
|
-
orig_count = file_safety.size
|
33
|
-
|
34
|
-
safety_repo = trunk_repo = get_trunk_repo
|
35
|
-
|
36
|
-
# TODO: below is broken for git-svn
|
37
|
-
# Is it needed?
|
38
|
-
|
39
|
-
SAFETY_REPOS.each do |suffix, alt|
|
40
|
-
# Temporarily override to only audit a different file list
|
41
|
-
if safety_repo.end_with?(suffix)
|
42
|
-
safety_repo = safety_repo[0...-suffix.length] + alt
|
43
|
-
break
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
if ignore_new
|
48
|
-
puts "Not checking for new files in #{safety_repo}"
|
49
|
-
else
|
50
|
-
puts "Checking for new files in #{safety_repo}"
|
51
|
-
new_files = get_new_files(safety_repo)
|
52
|
-
# Ignore subdirectories, and exclude code_safety.yml by default.
|
53
|
-
new_files.delete_if { |f| f =~ /[\/\\]$/ || f == SAFETY_FILE }
|
54
|
-
new_files.each do |f|
|
55
|
-
next if file_safety.key?(f)
|
56
|
-
file_safety[f] = {
|
57
|
-
'comments' => nil,
|
58
|
-
'reviewed_by' => nil,
|
59
|
-
'safe_revision' => nil }
|
60
|
-
end
|
61
|
-
File.open(SAFETY_FILE, 'w') do |file|
|
62
|
-
# Consistent file diffs, as ruby preserves Hash insertion order since v1.9
|
63
|
-
safety_cfg['file safety'] = Hash[file_safety.sort]
|
64
|
-
YAML.dump(safety_cfg, file) # Save changes before checking latest revisions
|
65
|
-
end
|
66
|
-
end
|
67
|
-
puts "Updating latest revisions for #{file_safety.size} files"
|
68
|
-
set_last_changed_revision(trunk_repo, file_safety, file_safety.keys)
|
69
|
-
puts "\nSummary:"
|
70
|
-
puts "Number of files originally in #{SAFETY_FILE}: #{orig_count}"
|
71
|
-
puts "Number of new files added: #{file_safety.size - orig_count}"
|
72
|
-
|
73
|
-
# Now generate statistics:
|
74
|
-
unknown = file_safety.values.select { |x| x['safe_revision'].nil? }
|
75
|
-
unsafe = file_safety.values.select do |x|
|
76
|
-
!x['safe_revision'].nil? && x['safe_revision'] != -1 &&
|
77
|
-
x['last_changed_rev'] != x['safe_revision'] &&
|
78
|
-
!(x['last_changed_rev'] =~ /^[0-9]+$/ && x['safe_revision'] =~ /^[0-9]+$/ &&
|
79
|
-
x['last_changed_rev'].to_i < x['safe_revision'].to_i)
|
80
|
-
end
|
81
|
-
puts "Number of files with no safe version: #{unknown.size}"
|
82
|
-
puts "Number of files which are no longer safe: #{unsafe.size}"
|
83
|
-
puts
|
84
|
-
printed = []
|
85
|
-
# We also print a third category: ones which are no longer in the repository
|
86
|
-
file_list =
|
87
|
-
if show_in_priority
|
88
|
-
file_safety.sort_by { |_k, v| v.nil? ? -100 : v['last_changed_rev'].to_i }.map(&:first)
|
89
|
-
else
|
90
|
-
file_safety.keys.sort
|
91
|
-
end
|
92
|
-
|
93
|
-
file_list.each do |f|
|
94
|
-
if print_file_safety(file_safety, trunk_repo, f, false, printed.size >= max_print)
|
95
|
-
printed << f
|
96
|
-
end
|
97
|
-
end
|
98
|
-
puts "... and #{printed.size - max_print} others" if printed.size > max_print
|
99
|
-
if show_diffs
|
100
|
-
puts
|
101
|
-
printed.each do |f|
|
102
|
-
print_file_diffs(file_safety, trunk_repo, f, user_name)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Returns `true` unless there are pending reviews:
|
107
|
-
unsafe.length.zero? && unknown.length.zero?
|
108
|
-
end
|
109
|
-
|
110
|
-
# Print summary details of a file's known safety
|
111
|
-
# If not verbose, only prints details for unsafe files
|
112
|
-
# Returns true if anything printed (or would have been printed if silent),
|
113
|
-
# or false otherwise.
|
114
|
-
def print_file_safety(file_safety, repo, fname, verbose = false, silent = false)
|
115
|
-
msg = "#{fname}\n "
|
116
|
-
entry = file_safety[fname]
|
117
|
-
msg += 'File not in audit list' if entry.nil?
|
118
|
-
|
119
|
-
if entry['safe_revision'].nil?
|
120
|
-
msg += 'No safe revision known'
|
121
|
-
msg += ", last changed #{entry['last_changed_rev']}" unless entry['last_changed_rev'].nil?
|
122
|
-
else
|
123
|
-
repolatest = entry['last_changed_rev'] # May have been prepopulated en mass
|
124
|
-
msg += 'Not in repository: ' if entry['last_changed_rev'] == -1
|
125
|
-
if (repolatest != entry['safe_revision']) &&
|
126
|
-
!(repolatest =~ /^[0-9]+$/ && entry['safe_revision'] =~ /^[0-9]+$/ &&
|
127
|
-
repolatest.to_i < entry['safe_revision'].to_i)
|
128
|
-
# (Allow later revisions to be treated as safe for svn)
|
129
|
-
msg += "No longer safe since revision #{repolatest}: "
|
130
|
-
else
|
131
|
-
return false unless verbose
|
132
|
-
msg += 'Safe: '
|
133
|
-
end
|
134
|
-
msg += "revision #{entry['safe_revision']} reviewed by #{entry['reviewed_by']}"
|
135
|
-
end
|
136
|
-
msg += "\n Comments: #{entry['comments']}" if entry['comments']
|
137
|
-
puts msg unless silent
|
138
|
-
true
|
139
|
-
end
|
140
|
-
|
141
|
-
def flag_file_as_safe(release, reviewed_by, comments, f)
|
142
|
-
safety_cfg = YAML.load_file(SAFETY_FILE)
|
143
|
-
file_safety = safety_cfg['file safety']
|
144
|
-
|
145
|
-
unless File.exist?(f)
|
146
|
-
abort("Error: Unable to flag non-existent file as safe: #{f}")
|
147
|
-
end
|
148
|
-
unless file_safety.key?(f)
|
149
|
-
file_safety[f] = {
|
150
|
-
'comments' => nil,
|
151
|
-
'reviewed_by' => :dummy, # dummy value, will be overwritten
|
152
|
-
'safe_revision' => nil }
|
153
|
-
end
|
154
|
-
entry = file_safety[f]
|
155
|
-
entry_orig = entry.dup
|
156
|
-
if comments.to_s.length > 0 && entry['comments'] != comments
|
157
|
-
entry['comments'] = if entry['comments'].to_s.empty?
|
158
|
-
comments
|
159
|
-
else
|
160
|
-
"#{entry['comments']}#{'.' unless entry['comments'].end_with?('.')} Revision #{release}: #{comments}"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
if entry['safe_revision']
|
164
|
-
unless release
|
165
|
-
abort("Error: File already has safe revision #{entry['safe_revision']}: #{f}")
|
166
|
-
end
|
167
|
-
if release.is_a?(Integer) && release < entry['safe_revision']
|
168
|
-
puts("Warning: Rolling back safe revision from #{entry['safe_revision']} to #{release} for #{f}")
|
169
|
-
end
|
170
|
-
end
|
171
|
-
entry['safe_revision'] = release
|
172
|
-
entry['reviewed_by'] = reviewed_by
|
173
|
-
if entry == entry_orig
|
174
|
-
puts "No changes when updating safe_revision to #{release || '[none]'} for #{f}"
|
175
|
-
else
|
176
|
-
File.open(SAFETY_FILE, 'w') do |file|
|
177
|
-
# Consistent file diffs, as ruby preserves Hash insertion order since v1.9
|
178
|
-
safety_cfg['file safety'] = Hash[file_safety.sort]
|
179
|
-
YAML.dump(safety_cfg, file) # Save changes before checking latest revisions
|
180
|
-
end
|
181
|
-
puts "Updated safe_revision to #{release || '[none]'} for #{f}"
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
# Determine the type of repository
|
186
|
-
def repository_type
|
187
|
-
@repository_type ||= if Dir.exist?('.svn') || system("svn info . > /dev/null 2>&1")
|
188
|
-
'svn'
|
189
|
-
elsif Dir.exist?('.git') && open('.git/config').grep(/svn/).any?
|
190
|
-
'git-svn'
|
191
|
-
elsif Dir.exist?('.git') && open('.git/config').grep(/git/).any?
|
192
|
-
'git'
|
193
|
-
else
|
194
|
-
'not known'
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def get_trunk_repo
|
199
|
-
case repository_type
|
200
|
-
when 'svn'
|
201
|
-
repo_info = %x[svn info]
|
202
|
-
puts 'svn case'
|
203
|
-
return repo_info.split("\n").select { |x| x =~ /^URL: / }.collect { |x| x[5..-1] }.first
|
204
|
-
when 'git-svn'
|
205
|
-
puts 'git-svn case'
|
206
|
-
repo_info = %x[git svn info]
|
207
|
-
return repo_info.split("\n").select { |x| x =~ /^URL: / }.collect { |x| x[5..-1] }.first
|
208
|
-
when 'git'
|
209
|
-
puts 'git case'
|
210
|
-
repo_info = %x[git remote -v]
|
211
|
-
return repo_info.split("\n").first[7..-9]
|
212
|
-
else
|
213
|
-
return 'Information not available. Unknown repository type'
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def get_new_files(safety_repo)
|
218
|
-
case repository_type
|
219
|
-
when 'svn', 'git-svn'
|
220
|
-
%x[svn ls -R "#{safety_repo}"].split("\n")
|
221
|
-
when 'git'
|
222
|
-
#%x[git ls-files --modified].split("\n")
|
223
|
-
%x[git ls-files].split("\n")
|
224
|
-
|
225
|
-
# TODO: Below is for remote repository - for testing use local files
|
226
|
-
#new_files = %x[git ls-files --modified #{safety_repo}].split("\n")
|
227
|
-
# TODO: Do we need the --modified option?
|
228
|
-
#new_files = %x[git ls-files --modified].split("\n")
|
229
|
-
else
|
230
|
-
[]
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# Fill in the latest changed revisions in a file safety map.
|
235
|
-
# (Don't write this data to the YAML file, as it is intrinsic to the SVN
|
236
|
-
# repository.)
|
237
|
-
def set_last_changed_revision(repo, file_safety, fnames)
|
238
|
-
dot_freq = (file_safety.size / 40.0).ceil # Print up to 40 progress dots
|
239
|
-
case repository_type
|
240
|
-
when 'git'
|
241
|
-
fnames = file_safety.keys if fnames.nil?
|
242
|
-
|
243
|
-
fnames.each_with_index do |f, i|
|
244
|
-
info = %x[git log -n 1 #{f}].split("\n").first[7..-1]
|
245
|
-
if info.nil? || info.empty?
|
246
|
-
file_safety[f]['last_changed_rev'] = -1
|
247
|
-
else
|
248
|
-
file_safety[f]['last_changed_rev'] = info
|
249
|
-
end
|
250
|
-
# Show progress
|
251
|
-
print '.' if (i % dot_freq) == 0
|
252
|
-
end
|
253
|
-
puts
|
254
|
-
when 'git-svn', 'svn'
|
255
|
-
fnames = file_safety.keys if fnames.nil?
|
256
|
-
|
257
|
-
fnames.each_with_index do |f, i|
|
258
|
-
last_revision = get_last_changed_revision(repo, f)
|
259
|
-
if last_revision.nil? || last_revision.empty?
|
260
|
-
file_safety[f]['last_changed_rev'] = -1
|
261
|
-
else
|
262
|
-
file_safety[f]['last_changed_rev'] = last_revision
|
263
|
-
end
|
264
|
-
# Show progress
|
265
|
-
print '.' if (i % dot_freq) == 0
|
266
|
-
end
|
267
|
-
puts
|
268
|
-
# NOTE: Do we need the following for retries?
|
269
|
-
# if retries && result.size != fnames.size && fnames.size > 1
|
270
|
-
# # At least one invalid (deleted file --> subsequent arguments ignored)
|
271
|
-
# # Try each file individually
|
272
|
-
# # (It would probably be safe to continue from the extra_info.size argument)
|
273
|
-
# puts "Retrying (got #{result.size}, expected #{fnames.size})" if debug >= 2
|
274
|
-
# result = []
|
275
|
-
# fnames.each{ |f|
|
276
|
-
# result += svn_info_entries([f], repo, false, debug)
|
277
|
-
# }
|
278
|
-
# end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
# Return the last changed revision
|
283
|
-
def get_last_changed_revision(repo, fname)
|
284
|
-
case repository_type
|
285
|
-
when 'git'
|
286
|
-
%x[git log -n 1 "#{fname}"].split("\n").first[7..-1]
|
287
|
-
when 'git-svn', 'svn'
|
288
|
-
begin
|
289
|
-
svn_info = %x[svn info -r head "#{repo}/#{fname}"]
|
290
|
-
rescue
|
291
|
-
puts 'we have an error in the svn info line'
|
292
|
-
end
|
293
|
-
begin
|
294
|
-
svn_info.match('Last Changed Rev: ([0-9]*)').to_a[1]
|
295
|
-
rescue
|
296
|
-
puts 'We have an error in getting the revision'
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
# Get mime type. Note that Git does not have this information
|
302
|
-
def get_mime_type(repo, fname)
|
303
|
-
case repository_type
|
304
|
-
when 'git'
|
305
|
-
'Git does not provide mime types'
|
306
|
-
when 'git-svn', 'svn'
|
307
|
-
%x[svn propget svn:mime-type "#{repo}/#{fname}"].chomp
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
# # Print file diffs, for code review
|
312
|
-
def print_file_diffs(file_safety, repo, fname, user_name)
|
313
|
-
entry = file_safety[fname]
|
314
|
-
repolatest = entry['last_changed_rev']
|
315
|
-
safe_revision = entry['safe_revision']
|
316
|
-
|
317
|
-
if safe_revision.nil?
|
318
|
-
first_revision = set_safe_revision
|
319
|
-
print_repo_file_diffs(repolatest, repo, fname, user_name, first_revision)
|
320
|
-
else
|
321
|
-
|
322
|
-
rev = get_last_changed_revision(repo, fname)
|
323
|
-
if rev
|
324
|
-
mime = get_mime_type(repo, fname)
|
325
|
-
end
|
326
|
-
|
327
|
-
print_repo_file_diffs(repolatest, repo, fname, user_name, safe_revision) if repolatest != safe_revision
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
# Returns first commit for git and 0 for svn in order to be used to display
|
332
|
-
# new files. Called from print_file_diffs
|
333
|
-
def set_safe_revision
|
334
|
-
case repository_type
|
335
|
-
when 'git'
|
336
|
-
%x[git rev-list --max-parents=0 HEAD].chomp
|
337
|
-
when 'git-svn', 'svn'
|
338
|
-
0
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def print_repo_file_diffs(repolatest, repo, fname, user_name, safe_revision)
|
343
|
-
require 'open3'
|
344
|
-
cmd = nil
|
345
|
-
case repository_type
|
346
|
-
when 'git'
|
347
|
-
cmd = ['git', '--no-pager', 'diff', '-b', "#{safe_revision}..#{repolatest}", fname]
|
348
|
-
when 'git-svn', 'svn'
|
349
|
-
cmd = ['svn', 'diff', '-r', "#{safe_revision.to_i}:#{repolatest.to_i}", '-x', '-b', "#{repo}/#{fname}"]
|
350
|
-
end
|
351
|
-
if cmd
|
352
|
-
puts(cmd.join(' '))
|
353
|
-
stdout_and_err_str, status = Open3.capture2e(*cmd)
|
354
|
-
puts(stdout_and_err_str)
|
355
|
-
else
|
356
|
-
puts 'Unknown repo'
|
357
|
-
end
|
358
|
-
|
359
|
-
puts %(To flag the changes to this file as safe, run:)
|
360
|
-
puts %( rake audit:safe release=#{repolatest} file=#{fname} reviewed_by=#{user_name} comments="")
|
361
|
-
puts
|
362
|
-
end
|
363
|
-
|
364
|
-
def release_valid?(release)
|
365
|
-
case repository_type
|
366
|
-
when 'svn', 'git-svn'
|
367
|
-
release =~ /\A[0-9][0-9]*\Z/
|
368
|
-
when 'git'
|
369
|
-
release =~ /\A[0-9a-f]{40}\Z/
|
370
|
-
else
|
371
|
-
false
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
def get_release
|
376
|
-
release = ENV['release']
|
377
|
-
release = nil if release == '0'
|
378
|
-
case repository_type
|
379
|
-
when 'svn', 'git-svn'
|
380
|
-
release.to_i
|
381
|
-
when 'git'
|
382
|
-
release
|
383
|
-
else
|
384
|
-
''
|
385
|
-
end
|
386
|
-
release
|
387
|
-
end
|
388
|
-
|
389
|
-
def clean_working_copy?
|
390
|
-
case repository_type
|
391
|
-
when 'svn'
|
392
|
-
system('svn status | grep -q [^AMCDG]')
|
393
|
-
when 'git', 'git-svn'
|
394
|
-
system('git diff --quiet HEAD')
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
namespace :audit do
|
399
|
-
desc "Audit safety of source code.
|
400
|
-
Usage: audit:code [max_print=n] [ignore_new=false|true] [show_diffs=false|true] [reviewed_by=usr]
|
401
|
-
|
402
|
-
File #{SAFETY_FILE} lists the safety and revision information
|
403
|
-
of the era source code. This task updates the list, and [TODO] warns about
|
404
|
-
files which have changed since they were last verified as safe."
|
405
|
-
task(:code) do
|
406
|
-
puts 'Usage: audit:code [max_print=n] [ignore_new=false|true] [show_diffs=false|true] [show_in_priority=false|true] [reviewed_by=usr]'
|
407
|
-
puts "This is a #{repository_type} repository"
|
408
|
-
|
409
|
-
ignore_new = (ENV['ignore_new'].to_s =~ /\Atrue\Z/i)
|
410
|
-
show_diffs = (ENV['show_diffs'].to_s =~ /\Atrue\Z/i)
|
411
|
-
show_in_priority = (ENV['show_in_priority'].to_s =~ /\Atrue\Z/i)
|
412
|
-
max_print = ENV['max_print'] =~ /\A-?[0-9][0-9]*\Z/ ? ENV['max_print'].to_i : 20
|
413
|
-
reviewer = ENV['reviewed_by']
|
414
|
-
|
415
|
-
all_safe = audit_code_safety(max_print, ignore_new, show_diffs, show_in_priority, reviewer)
|
416
|
-
|
417
|
-
unless show_diffs
|
418
|
-
puts 'To show file diffs, run: rake audit:code max_print=-1 show_diffs=true'
|
419
|
-
end
|
420
|
-
|
421
|
-
exit(1) unless all_safe
|
422
|
-
end
|
423
|
-
|
424
|
-
desc "Flag a source file as safe.
|
425
|
-
|
426
|
-
Usage:
|
427
|
-
Flag as safe: rake audit:safe release=revision reviewed_by=usr [comments=...] file=f
|
428
|
-
Needs review: rake audit:safe release=0 [comments=...] file=f"
|
429
|
-
task(:safe) do
|
430
|
-
release = get_release
|
431
|
-
|
432
|
-
required_fields = %w(release file)
|
433
|
-
required_fields << 'reviewed_by' if release # 'Needs review' doesn't need a reviewer
|
434
|
-
missing = required_fields.collect { |f| (f if ENV[f].to_s.empty? || (f == 'reviewed_by' && ENV[f] == 'usr')) }.compact # Avoid accidental missing username
|
435
|
-
unless missing.empty?
|
436
|
-
puts 'Usage: rake audit:safe release=revision reviewed_by=usr [comments=...] file=f'
|
437
|
-
puts 'or, to flag a file for review: rake audit:safe release=0 [comments=...] file=f'
|
438
|
-
abort("Error: Missing required argument(s): #{missing.join(', ')}")
|
439
|
-
end
|
440
|
-
|
441
|
-
unless release.nil? || release_valid?(release)
|
442
|
-
puts 'Usage: rake audit:safe release=revision reviewed_by=usr [comments=...] file=f'
|
443
|
-
puts 'or, to flag a file for review: rake audit:safe release=0 [comments=...] file=f'
|
444
|
-
abort("Error: Invalid release: #{ENV['release']}")
|
445
|
-
end
|
446
|
-
|
447
|
-
flag_file_as_safe(release, ENV['reviewed_by'], ENV['comments'], ENV['file'])
|
448
|
-
end
|
449
|
-
|
450
|
-
desc 'Wraps audit:code, and stops if any review is pending/stale.'
|
451
|
-
task(:ensure_safe) do
|
452
|
-
abort('You have local changes, cannot verify code safety!') unless clean_working_copy?
|
453
|
-
|
454
|
-
puts 'Checking code safety...'
|
455
|
-
|
456
|
-
begin
|
457
|
-
begin
|
458
|
-
$stdout = $stderr = StringIO.new
|
459
|
-
Rake::Task['audit:code'].invoke
|
460
|
-
ensure
|
461
|
-
$stdout, $stderr = STDOUT, STDERR
|
462
|
-
end
|
463
|
-
rescue SystemExit => ex
|
464
|
-
puts '=============================================================='
|
465
|
-
puts 'Code safety review of some files are not up-to-date; aborting!'
|
466
|
-
puts ' - to review the files in question, run: rake audit:code'
|
467
|
-
puts '=============================================================='
|
468
|
-
|
469
|
-
raise ex
|
470
|
-
end
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
# Prevent building of un-reviewed gems:
|
475
|
-
task build: :'audit:ensure_safe'
|