risk-summary 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d4780eacae71f76f5f028a5fab5a6ff33474923d2dfdf1f4c1ecab4389af0ba2
4
+ data.tar.gz: b042d1f8910db7ae3361925ed1b4f901782daefeb9a265af63cdcb3e854f3de7
5
+ SHA512:
6
+ metadata.gz: b530af8e6538860b2969aadf48037773019ec78090b3c42eebb49cc45b83b25cdc0724768d4737264ff2d2e871b5346e6ef80bc97ac5103eaaa69f19e8373c85
7
+ data.tar.gz: 8194da7f773597567a3fa5f1f10a125d1c5496398f1c24fb3e16cc523ef626eb2e005f18c279d75a592f61f3a8961992c099ffbf67a025634b48c8f4d909c8d1
@@ -0,0 +1,20 @@
1
+ Copyright (C) 2013 Michael Grosser <michael@grosser.it>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ require "risk_summary"
4
+ exit RiskSummary.cli(ARGV)
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ require "risk_summary/version"
3
+ require "optparse"
4
+ require "net/http"
5
+ require "json"
6
+
7
+ module RiskSummary
8
+ # copied from https://github.com/zendesk/samson/blob/master/app/models/changeset/pull_request.rb
9
+ # modified to use unsafe regex stripping
10
+ module RiskParser
11
+ class << self
12
+ def parse(text)
13
+ return :missing unless section = risk_section(text)
14
+ return :missing if section.strip.empty?
15
+ return :none if section.match?(/\A\s*-?\s*None\Z/i)
16
+ section
17
+ end
18
+
19
+ private
20
+
21
+ def risk_section(body)
22
+ body_stripped = body.gsub(%r{</?[^>]+?>}, "") # not safe, but much simpler than pulling in nokogiri
23
+ return nil unless section = section_content('Risks', body_stripped)
24
+ section.rstrip.sub(/\A\s*\n/, "")
25
+ end
26
+
27
+ def section_content(section_title, text)
28
+ # ### Risks or Risks followed by === / ---
29
+ desired_header_regexp = "^(?:\\s*#+\\s*#{section_title}.*|\\s*#{section_title}.*\\n\\s*(?:-{2,}|={2,}))\\n"
30
+ content_regexp = '([\W\w]*?)' # capture all section content, including new lines, but not next header
31
+ next_header_regexp = '(?=^(?:\s*#+|.*\n\s*(?:-{2,}|={2,}\s*\n))|\z)'
32
+
33
+ text[/#{desired_header_regexp}#{content_regexp}#{next_header_regexp}/i, 1]
34
+ end
35
+ end
36
+ end
37
+
38
+ class << self
39
+ def cli(argv)
40
+ parse_cli_options! argv
41
+ token = ENV["GITHUB_TOKEN"] || token_from_gitconfig
42
+ puts risks(*argv, token)
43
+ 0
44
+ end
45
+
46
+ private
47
+
48
+ def risks(repo, diff, token)
49
+ compare = http_get "/repos/#{repo}/compare/#{diff}", token
50
+
51
+ pulls = parallel(compare.fetch(:commits), threads: 10) do |commit|
52
+ http_get "/repos/#{repo}/commits/#{commit.fetch(:sha)}/pulls", token
53
+ end.flatten(1).uniq
54
+
55
+ pulls.map do |pull|
56
+ risks = RiskParser.parse(pull.fetch(:body))
57
+ case risks
58
+ when :missing then "- missing risks from [##{pull.fetch(:number)}](#{pull.fetch(:html_url)})"
59
+ when :none then nil
60
+ else risks
61
+ end
62
+ end.compact
63
+ end
64
+
65
+ def parse_cli_options!(argv)
66
+ parser = OptionParser.new do |p|
67
+ p.banner = <<~BANNER
68
+ Collects Risk section from all merged PRs over a given commit range.
69
+ Your github token needs to be available as `GITHUB_TOKEN` env var or `git config github.token`.
70
+
71
+ Usage:
72
+ risk-summary zendesk/samson v3240...v3250
73
+
74
+ Options:
75
+ BANNER
76
+ p.on("-h", "--help", "Show this.") do
77
+ puts p
78
+ exit 0
79
+ end
80
+ p.on("-v", "--version", "Show Version") do
81
+ puts VERSION
82
+ exit 0
83
+ end
84
+ end
85
+ parser.parse!(argv)
86
+
87
+ if argv.size != 2
88
+ puts parser
89
+ exit 1
90
+ end
91
+ end
92
+
93
+ def token_from_gitconfig
94
+ result = `git config github.token`.chomp
95
+ result if $?.success?
96
+ end
97
+
98
+ def http_get(path, token)
99
+ url = "https://api.github.com#{path}"
100
+ uri = URI(url)
101
+ req = Net::HTTP::Get.new(uri)
102
+ req["Authorization"] = "token #{token}" if token
103
+ req["Accept"] = "application/vnd.github.groot-preview+json" # for /pulls requests
104
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
105
+ http.request(req)
106
+ end
107
+ raise "Bad response #{res.code} from #{url}:\n#{res.body}" unless res.code == "200"
108
+ JSON.parse(res.body, symbolize_names: true)
109
+ end
110
+
111
+ def parallel(items, threads:)
112
+ results = Array.new(items.size)
113
+ items = items.each_with_index.to_a
114
+
115
+ Array.new([threads, items.size].min) do
116
+ Thread.new do
117
+ loop do
118
+ item, index = items.pop
119
+ break unless index
120
+ results[index] = yield item
121
+ end
122
+ end
123
+ end.each(&:join)
124
+
125
+ results
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RiskSummary
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: risk-summary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: michael@grosser.it
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - MIT-LICENSE
20
+ - bin/risk-summary
21
+ - lib/risk_summary.rb
22
+ - lib/risk_summary/version.rb
23
+ homepage: https://github.com/grosser/risk-summary
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 2.5.0
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.1.3
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Collects Risk section from all merged PRs over a given commit range
46
+ test_files: []