pivotoolz 1.3.0 → 2.3.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: 7c0a93ab211a7ca9fdf96b3411b55af12aff671d8b9917b59c78d3ad32d39e76
4
- data.tar.gz: 7e30198b5f17a1c9d07eb1c5cab65cee1b4ac36b2bb441a3301c3871f53d6258
3
+ metadata.gz: 648b707a351eb4f2b97c0a8a336f4bf7ac8efb96b9b619a903643d870839d136
4
+ data.tar.gz: d967f3097e9e3892aea0a4886e222a08780926afd200596aa9eec7215a56bc53
5
5
  SHA512:
6
- metadata.gz: e8cebaeabffee302c4af7a1507aa755daada1fd7afe57bf4189574f3f40910e48cfa5aeda40297bed2f32f08e519fb2abbe4e38385838036ef5be3c6743a45de
7
- data.tar.gz: 7ece7827562f290a8a67859a83370afa67fbb61c383ad7e77ed3700c91674003121f7c2b55bc45a4146d85800e3be5de40eb00952222af63d1c968f1a2170c18
6
+ metadata.gz: d9e1e27ad6af6380c1c4842a8c54459aa734d3d00c82aeb5d48197797c5034389a3832c92bfbbbd46012318caf2610c134452240b030cbb3bfc5c4fc644bf310
7
+ data.tar.gz: 1ecc3da31218e2b0b989f569b3d50f3715d3d934ef8aa33ce8efe804185d114bdbe57dbe9f0283435e15a98b7ec63e6a8521d5e4764a3e67b1750871308d176f
data/Gemfile.lock CHANGED
@@ -1,51 +1,53 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pivotoolz (1.3.0)
5
- rest-client (~> 2.0.2)
4
+ pivotoolz (2.2.0)
5
+ rest-client (~> 2.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- diff-lcs (1.3)
10
+ diff-lcs (1.4.4)
11
11
  domain_name (0.5.20190701)
12
12
  unf (>= 0.0.5, < 1.0.0)
13
- http-cookie (1.0.3)
13
+ http-accept (1.7.0)
14
+ http-cookie (1.0.4)
14
15
  domain_name (~> 0.5)
15
- mime-types (3.3)
16
+ mime-types (3.3.1)
16
17
  mime-types-data (~> 3.2015)
17
- mime-types-data (3.2019.1009)
18
+ mime-types-data (3.2021.0901)
18
19
  netrc (0.11.0)
19
- rake (10.4.2)
20
- rest-client (2.0.2)
20
+ rake (13.0.6)
21
+ rest-client (2.1.0)
22
+ http-accept (>= 1.7.0, < 2.0)
21
23
  http-cookie (>= 1.0.2, < 2.0)
22
24
  mime-types (>= 1.16, < 4.0)
23
25
  netrc (~> 0.8)
24
- rspec (3.6.0)
25
- rspec-core (~> 3.6.0)
26
- rspec-expectations (~> 3.6.0)
27
- rspec-mocks (~> 3.6.0)
28
- rspec-core (3.6.0)
29
- rspec-support (~> 3.6.0)
30
- rspec-expectations (3.6.0)
26
+ rspec (3.10.0)
27
+ rspec-core (~> 3.10.0)
28
+ rspec-expectations (~> 3.10.0)
29
+ rspec-mocks (~> 3.10.0)
30
+ rspec-core (3.10.1)
31
+ rspec-support (~> 3.10.0)
32
+ rspec-expectations (3.10.1)
31
33
  diff-lcs (>= 1.2.0, < 2.0)
32
- rspec-support (~> 3.6.0)
33
- rspec-mocks (3.6.0)
34
+ rspec-support (~> 3.10.0)
35
+ rspec-mocks (3.10.2)
34
36
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.6.0)
36
- rspec-support (3.6.0)
37
+ rspec-support (~> 3.10.0)
38
+ rspec-support (3.10.2)
37
39
  unf (0.1.4)
38
40
  unf_ext
39
- unf_ext (0.0.7.6)
41
+ unf_ext (0.0.8)
40
42
 
41
43
  PLATFORMS
42
44
  ruby
43
45
 
44
46
  DEPENDENCIES
45
- bundler (~> 1.16)
47
+ bundler (~> 2.2)
46
48
  pivotoolz!
47
- rake (~> 10.0)
48
- rspec (~> 3.0)
49
+ rake (~> 13.0)
50
+ rspec (~> 3.10)
49
51
 
50
52
  BUNDLED WITH
51
- 1.17.2
53
+ 2.2.27
@@ -11,7 +11,7 @@ def get_story_info(story_id, flags = [])
11
11
  begin
12
12
  include_owner_names = flags.any? { |f| f == '--owners' || f == '-O' }
13
13
  url = BASE_URL + "#{story_id}" + "/#{include_owner_names ? '?fields=:default,owners' : ''}"
14
- open(
14
+ URI.open(
15
15
  url,
16
16
  'X-TrackerToken' => ENV['PIVOTAL_TRACKER_API_TOKEN']
17
17
  ).read
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'open-uri'
4
+ require 'json'
5
+
6
+ BASE_URL = ENV['JIRA_API_BASE_URL']
7
+
8
+ def get_story_info(story_id, flags = [], subdomain)
9
+ return nil if story_id.empty?
10
+
11
+ begin
12
+ url = BASE_URL + "#{story_id}"
13
+ URI.open(
14
+ url,
15
+ 'Authorization' => "Basic #{ENV['JIRA_API_BASIC_AUTH_BASE64_ENCODED']}"
16
+ ).read
17
+ rescue StandardError => e
18
+ story_link = "https://#{subdomain}.atlassian.net/browse/#{story_id}"
19
+
20
+ JSON.generate({
21
+ error: "Could not get story info for story #{story_id}: #{e.message}\n\nStory info may be available at #{story_link}",
22
+ story_link: story_link
23
+ })
24
+ end
25
+ end
26
+
27
+ if BASE_URL.nil? || BASE_URL.empty?
28
+ puts "Please set JIRA_API_BASE_URL. It looks something like 'https://YOUR-COMPANY.atlassian.net/rest/api/2/issue/'"
29
+ exit 1
30
+ end
31
+
32
+ begin
33
+ subdomain = URI.parse(BASE_URL).host.split('.atlassian.net').first
34
+ rescue => e
35
+ puts "Error determining your Jira subdomain. Please check your JIRA_API_BASE_URL environment variable"
36
+ exit 1
37
+ end
38
+
39
+ flags = ARGV.reduce([]) do |reduced, a|
40
+ reduced << a if a.include?('--') || a.include?('-')
41
+ reduced
42
+ end
43
+
44
+ flags.each { |f| ARGV.delete f }
45
+
46
+ stream = ARGV.any? ? ARGV : ARGF
47
+
48
+ if stream == ARGF && $stdin.tty?
49
+ puts "Usage:\nget-story-info-from-jira-id STORY_ID\n"
50
+ puts " OR\n"
51
+ puts "echo STORY_ID | get-story-info-from-id"
52
+ puts " OR\n"
53
+ exit 1
54
+ end
55
+
56
+ infos = stream.reduce([]) do |reduced, story_id|
57
+ next reduced unless story_id && story_id =~ /\d+/
58
+ reduced << get_story_info(story_id.strip, flags, subdomain)
59
+ end
60
+
61
+ puts infos.join("\n")
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+ require 'ostruct'
5
+ require 'uri'
6
+
7
+ BASE_URL = ENV['JIRA_API_BASE_URL']
8
+
9
+ if BASE_URL.nil? || BASE_URL.empty?
10
+ puts "Please set JIRA_API_BASE_URL. It looks something like 'https://YOUR-COMPANY.atlassian.net/rest/api/2/issue/'"
11
+ exit 1
12
+ end
13
+
14
+ begin
15
+ subdomain = URI.parse(BASE_URL).host.split('.atlassian.net').first
16
+ rescue => e
17
+ puts "Error determining your Jira subdomain. Please check your JIRA_API_BASE_URL environment variable"
18
+ exit 1
19
+ end
20
+
21
+ environment_tag = ARGV[0]&.strip
22
+ if environment_tag.nil? || environment_tag.empty?
23
+ puts "Usage: stories-deployed ENVIRONMENT"
24
+ exit 1
25
+ end
26
+
27
+ flags = ARGV.select { |a| a.include?('--') || a.include?('-') }
28
+
29
+ include_owners = flags
30
+ .any? { |f| f == '--owners' || f == '-O' }
31
+
32
+ format_as_json = flags
33
+ .any? { |f| f == '--json' || f == '-j' }
34
+
35
+ deployed_story_infos = `jira-story-ids-deployed #{environment_tag} | get-story-info-from-jira-id #{flags.join(' ')}`
36
+
37
+ def as_json(story, include_owners, flags, subdomain)
38
+ if story.error
39
+ return {
40
+ title: story.error,
41
+ title_link: story.story_link
42
+ }.to_json
43
+ end
44
+
45
+ json = {
46
+ title: story.fields['summary']&.strip,
47
+ title_link: "https://#{subdomain}.atlassian.net/browse/#{story.key}",
48
+ mrkdwn_in: ["text", "pretext", "footer"]
49
+ }
50
+
51
+ if include_owners
52
+ if flags.include? '--owners-footer'
53
+ json.merge!(
54
+ footer: "\n\nBrought to you by: #{story_owner_names(story, flags)}"
55
+ )
56
+ else
57
+ json.merge!(
58
+ text: "\n\nBrought to you by: #{story_owner_names(story, flags)}"
59
+ )
60
+ end
61
+ end
62
+
63
+ json.to_json
64
+ end
65
+
66
+ def story_owner_names(story, flags)
67
+ owners = *(
68
+ story
69
+ .fields
70
+ .assignee
71
+ &.displayName
72
+ )
73
+
74
+ if flags.include? '--bold-owners'
75
+ return to_sentence(owners.map { |o| "*#{o}*" })
76
+ end
77
+
78
+ to_sentence(owners)
79
+ end
80
+
81
+ def to_sentence(array)
82
+ array.size > 2 ?
83
+ "#{array[0..-2].join(', ')} and #{array.last}" :
84
+ array.join(' and ')
85
+ end
86
+
87
+ stories_deployed = deployed_story_infos
88
+ .split("\n")
89
+ .compact
90
+ .reduce([]) do |reduced, story_info|
91
+ story = JSON.parse(story_info, object_class: OpenStruct)
92
+
93
+ if format_as_json
94
+ reduced << as_json(story, include_owners, flags, subdomain)
95
+ next reduced
96
+ end
97
+
98
+ reduced << "#{story.error}"
99
+ next reduced if story.error
100
+
101
+ reduced << "#{story.name&.strip}:\n#{story.url}"
102
+
103
+ if include_owners
104
+ reduced << "\nBrought to you by: #{story_owner_names(story, flags)}"
105
+ end
106
+
107
+ reduced
108
+ end
109
+
110
+ puts stories_deployed
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ environment_tag = ARGV[0]&.strip
4
+
5
+ if environment_tag.nil? || environment_tag.empty?
6
+ puts "Usage: story-ids-deployed ENVIRONMENT"
7
+ exit 1
8
+ end
9
+
10
+ commit_range = `git tag -l #{environment_tag}* | tail -n 2 | tr '\n' ' ' | sed -e 's/ /../'`.strip
11
+
12
+ if commit_range.nil? || commit_range.empty?
13
+ puts "Empty commit range! Are there any commits tagged with #{environment_tag}?"
14
+ exit 1
15
+ end
16
+
17
+ commit_message_bodies = `git log --pretty="%h %s" #{commit_range}`.strip
18
+ story_ids = commit_message_bodies.
19
+ # TODO: Make this configurable
20
+ scan(/(DI-\d+|ST-\d+)/).
21
+ flatten.
22
+ compact.
23
+ uniq
24
+
25
+ puts story_ids.join("\n")
@@ -2,42 +2,32 @@
2
2
 
3
3
  require 'rest-client'
4
4
  require 'json'
5
+ require_relative '../lib/pivotoolz/post_slack_message'
5
6
 
6
- URL = ENV['SLACK_WEBHOOK_URL']
7
+ URL = ENV.fetch('SLACK_WEBHOOK_URL') { '' }
8
+ CHANNEL_URL_MAP = ENV.fetch('SLACK_WEBHOOK_CHANNEL_URLS') { {} }
9
+
10
+ if URL.empty? && CHANNEL_URL_MAP.empty?
11
+ puts "Need either SLACK_WEBHOOK_URL or SLACK_WEBHOOK_CHANNEL_URLS to be defined!"
12
+ exit 0
13
+ end
7
14
 
8
15
  channel = ARGV.shift
16
+ if channel.to_s.empty?
17
+ puts "Channel to post to is required!!"
18
+ exit 0
19
+ end
20
+
9
21
  content = ARGV.empty? ? ARGF.read : StringIO.new(ARGV.join("\n")).read
10
22
  exit 0 if content.strip.empty?
11
23
 
12
- begin
13
- text, *json = content.split("\n")
14
- if !json.empty?
15
- post_data = json.any? { |s| s.include? 'blocks' } ? JSON.parse(json.first) : {attachments: json.map { |j| JSON.parse(j) }}
16
- begin
17
- RestClient.post(
18
- URL,
19
- post_data.merge({text: text || ''}).to_json,
20
- {content_type: :json, accept: :json}
21
- )
22
- rescue RestClient::Exceptions => e
23
- puts "Error posting to slack #{e.message}:\n#{e.backtrace}"
24
- end
25
-
26
- exit 0
27
- end
28
- rescue JSON::ParserError => e
29
- end
24
+ psm = PostSlackMessage.new
25
+ webhook_url = psm.select_webhook_url(URL, CHANNEL_URL_MAP, channel)
30
26
 
31
- begin
32
- RestClient.post(
33
- URL,
34
- payload: {
35
- username: ENV['SLACKBOT_USERNAME'] || 'slackbot',
36
- channel: channel,
37
- text: content,
38
- icon_emoji: ":ghost:"
39
- }.to_json
40
- )
41
- rescue RestClient::Exceptions => e
42
- puts "Error posting to slack #{e.message}:\n#{e.backtrace}"
27
+ if webhook_url.nil?
28
+ puts "Channel '#{channel}' webhook url not found! Please define it in SLACK_WEBHOOK_CHANNEL_URLS environment variable"
29
+ exit 0
43
30
  end
31
+
32
+ result = psm.post_message(webhook_url, channel, content)
33
+ puts result if !result.empty?
@@ -0,0 +1,51 @@
1
+ class PostSlackMessage
2
+ def select_webhook_url(url, channel_map, channel)
3
+ return url if channel_map.empty?
4
+
5
+ channel_webhook_map = channel_map.split(',').reduce({}) do |reduced, channel_map_string|
6
+ c, url = channel_map_string.split('->')
7
+ reduced[c] = url
8
+ reduced["@#{c}"] = url if !c.start_with?('@')
9
+ reduced["##{c}"] = url if !c.start_with?('#')
10
+ reduced
11
+ end
12
+
13
+ channel_webhook_map[channel]
14
+ end
15
+
16
+ def post_message(url, channel, content)
17
+ begin
18
+ text, *json = content.split("\n")
19
+ return post_basic_message(url, channel, content) if json.empty?
20
+
21
+ post_data = json.any? { |s| s.include? 'blocks' } ? JSON.parse(json.first) : {attachments: json.map { |j| JSON.parse(j) }}
22
+ begin
23
+ RestClient.post(
24
+ url,
25
+ post_data.merge({text: text || ''}).to_json,
26
+ {content_type: :json, accept: :json}
27
+ )
28
+ rescue RestClient::Exceptions => e
29
+ return "Error posting to slack #{e.message}:\n#{e.backtrace}"
30
+ end
31
+ rescue JSON::ParserError => e
32
+ "Error parsing json: #{e}"
33
+ end
34
+ end
35
+
36
+ def post_basic_message(url, channel, content)
37
+ begin
38
+ RestClient.post(
39
+ url,
40
+ payload: {
41
+ username: ENV['SLACKBOT_USERNAME'] || 'slackbot',
42
+ channel: channel,
43
+ text: content,
44
+ icon_emoji: ":ghost:"
45
+ }.to_json
46
+ )
47
+ rescue RestClient::Exceptions => e
48
+ puts "Error posting to slack #{e.message}:\n#{e.backtrace}"
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,3 @@
1
1
  module Pivotoolz
2
- VERSION = "1.3.0"
2
+ VERSION = "2.3.0"
3
3
  end
data/pivotoolz.gemspec CHANGED
@@ -28,9 +28,9 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ["lib"]
30
30
 
31
- spec.add_dependency 'rest-client', "~> 2.0.2"
31
+ spec.add_dependency 'rest-client', "~> 2.1"
32
32
 
33
- spec.add_development_dependency "bundler", "~> 1.16"
34
- spec.add_development_dependency "rake", "~> 10.0"
35
- spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_development_dependency "bundler", "~> 2.2"
34
+ spec.add_development_dependency "rake", "~> 13.0"
35
+ spec.add_development_dependency "rspec", "~> 3.10"
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pivotoolz
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sufyan Adam
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-27 00:00:00.000000000 Z
11
+ date: 2021-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.2
19
+ version: '2.1'
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: 2.0.2
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.16'
33
+ version: '2.2'
34
34
  type: :development
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: '1.16'
40
+ version: '2.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '3.10'
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: '3.0'
68
+ version: '3.10'
69
69
  description: Auto-deliver your finished stories upon successful deployment, find out
70
70
  which stories went out in the last deployment, get a list of pivotal tracker story
71
71
  ids that went out in the last deployment.
@@ -75,6 +75,9 @@ executables:
75
75
  - deliver-deployed-stories
76
76
  - deliver-story
77
77
  - get-story-info-from-id
78
+ - get-story-info-from-jira-id
79
+ - jira-stories-deployed
80
+ - jira-story-ids-deployed
78
81
  - merge
79
82
  - post-slack-message
80
83
  - pv-git-branch
@@ -104,6 +107,9 @@ files:
104
107
  - exe/deliver-deployed-stories
105
108
  - exe/deliver-story
106
109
  - exe/get-story-info-from-id
110
+ - exe/get-story-info-from-jira-id
111
+ - exe/jira-stories-deployed
112
+ - exe/jira-story-ids-deployed
107
113
  - exe/merge
108
114
  - exe/post-slack-message
109
115
  - exe/pv-git-branch
@@ -112,6 +118,7 @@ files:
112
118
  - exe/tag-it
113
119
  - lib/pivotoolz.rb
114
120
  - lib/pivotoolz/git_branch.rb
121
+ - lib/pivotoolz/post_slack_message.rb
115
122
  - lib/pivotoolz/version.rb
116
123
  - pivotoolz.gemspec
117
124
  homepage: https://github.com/sufyanadam/pivotoolz
@@ -119,7 +126,7 @@ licenses:
119
126
  - MIT
120
127
  metadata:
121
128
  allowed_push_host: https://rubygems.org
122
- post_install_message:
129
+ post_install_message:
123
130
  rdoc_options: []
124
131
  require_paths:
125
132
  - lib
@@ -134,8 +141,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
141
  - !ruby/object:Gem::Version
135
142
  version: '0'
136
143
  requirements: []
137
- rubygems_version: 3.0.3
138
- signing_key:
144
+ rubygems_version: 3.2.3
145
+ signing_key:
139
146
  specification_version: 4
140
147
  summary: Tools to save you time when working with Pivotal Tracker stories
141
148
  test_files: []