smart_todo 1.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 +7 -0
- data/.gitignore +8 -0
- data/.rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml +1027 -0
- data/.rubocop.yml +5 -0
- data/.shopify-build/VERSION +1 -0
- data/.shopify-build/smart-todo.yml +37 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +50 -0
- data/LICENSE.txt +21 -0
- data/README.md +49 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/rubocop +29 -0
- data/bin/setup +8 -0
- data/dev.yml +11 -0
- data/exe/smart_todo +14 -0
- data/lib/smart_todo/cli.rb +74 -0
- data/lib/smart_todo/dispatcher.rb +99 -0
- data/lib/smart_todo/events/date.rb +26 -0
- data/lib/smart_todo/events/gem_release.rb +69 -0
- data/lib/smart_todo/events/pull_request_close.rb +86 -0
- data/lib/smart_todo/events.rb +52 -0
- data/lib/smart_todo/parser/comment_parser.rb +71 -0
- data/lib/smart_todo/parser/metadata_parser.rb +116 -0
- data/lib/smart_todo/parser/todo_node.rb +43 -0
- data/lib/smart_todo/slack_client.rb +113 -0
- data/lib/smart_todo/version.rb +5 -0
- data/lib/smart_todo.rb +22 -0
- data/lib/smart_todo_cop.rb +37 -0
- data/shipit.rubygems.yml +1 -0
- data/smart_todo.gemspec +38 -0
- metadata +152 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module SmartTodo
|
7
|
+
# A simple client around the Slack API.
|
8
|
+
#
|
9
|
+
# @example Sending a message to a user.
|
10
|
+
# SmartTodo::SlackClient.new.post_message('#general', 'Hello!')
|
11
|
+
class SlackClient
|
12
|
+
# A generic error class raised when the Slack API returns back a 200
|
13
|
+
# but there was a problem (permission issues ...)
|
14
|
+
class Error < StandardError
|
15
|
+
attr_reader :error_code
|
16
|
+
|
17
|
+
# @param response_body [Hash] the parsed response body from Slack
|
18
|
+
def initialize(response_body)
|
19
|
+
@error_code = response_body['error']
|
20
|
+
|
21
|
+
super("Response body: #{response_body}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param slack_token [String]
|
26
|
+
def initialize(slack_token)
|
27
|
+
@slack_token = slack_token
|
28
|
+
@client = Net::HTTP.new('slack.com', Net::HTTP.https_default_port).tap do |client|
|
29
|
+
client.use_ssl = true
|
30
|
+
client.read_timeout = 30
|
31
|
+
client.ssl_timeout = 15
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Retrieve the Slack ID of a user from his email
|
36
|
+
#
|
37
|
+
# @param email [String]
|
38
|
+
# @return [Hash]
|
39
|
+
#
|
40
|
+
# @raise [Net::HTTPError] in case the reques to Slack failed
|
41
|
+
# @raise [SlackClient::Error] in case Slack returs a { ok: false } in the body
|
42
|
+
#
|
43
|
+
# @see https://api.slack.com/methods/users.lookupByEmail
|
44
|
+
def lookup_user_by_email(email)
|
45
|
+
headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
46
|
+
|
47
|
+
request(:get, "/api/users.lookupByEmail?email=#{email}", nil, headers)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Send a message to a Slack channel or to a user
|
51
|
+
#
|
52
|
+
# @param channel [String] The Slack channel or the user ID
|
53
|
+
# @param text [String] The message to send
|
54
|
+
# @return [Hash]
|
55
|
+
#
|
56
|
+
# @raise [Net::HTTPError] in case the reques to Slack failed
|
57
|
+
# @raise [SlackClient::Error] in case Slack returs a { ok: false } in the body
|
58
|
+
#
|
59
|
+
# @see https://api.slack.com/methods/chat.postMessage
|
60
|
+
def post_message(channel, text)
|
61
|
+
request(:post, '/api/chat.postMessage', JSON.dump(channel: channel, text: text))
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# @param method [Symbol]
|
67
|
+
# @param endpoint [String]
|
68
|
+
# @param data [String] JSON encoded data when making a POST request
|
69
|
+
# @param headers [Hash]
|
70
|
+
#
|
71
|
+
# @raise [Net::HTTPError] in case the reques to Slack failed
|
72
|
+
# @raise [SlackClient::Error] in case Slack returs a { ok: false } in the body
|
73
|
+
def request(method, endpoint, data = nil, headers = {})
|
74
|
+
response = case method
|
75
|
+
when :post, :patch
|
76
|
+
@client.public_send(method, endpoint, data, default_headers.merge(headers))
|
77
|
+
else
|
78
|
+
@client.public_send(method, endpoint, default_headers.merge(headers))
|
79
|
+
end
|
80
|
+
|
81
|
+
slack_response!(response)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Chech if the response to Slack was a 200 and the Slack API request was successful
|
85
|
+
#
|
86
|
+
# @param response [Net::HTTPResponse] a net Net::HTTPResponse subclass
|
87
|
+
# (Net::HTTPOK, Net::HTTPNotFound ...)
|
88
|
+
# @return [Hash]
|
89
|
+
#
|
90
|
+
# @raise [Net::HTTPError] in case the reques to Slack failed
|
91
|
+
# @raise [SlackClient::Error] in case Slack returs a { ok: false } in the body
|
92
|
+
def slack_response!(response)
|
93
|
+
raise(Net::HTTPError.new('Request to slack failed', response)) unless response.code_type < Net::HTTPSuccess
|
94
|
+
body = JSON.parse(response.body)
|
95
|
+
|
96
|
+
if body['ok']
|
97
|
+
body
|
98
|
+
else
|
99
|
+
raise(Error, body)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# The default headers required by Slack
|
104
|
+
#
|
105
|
+
# @return [Hash]
|
106
|
+
def default_headers
|
107
|
+
{
|
108
|
+
'Content-Type' => 'application/json; charset=utf8',
|
109
|
+
'Authorization' => "Bearer #{@slack_token}",
|
110
|
+
}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/smart_todo.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "smart_todo/version"
|
4
|
+
require "smart_todo/events"
|
5
|
+
|
6
|
+
module SmartTodo
|
7
|
+
autoload :SlackClient, 'smart_todo/slack_client'
|
8
|
+
autoload :CLI, 'smart_todo/cli'
|
9
|
+
autoload :Dispatcher, 'smart_todo/dispatcher'
|
10
|
+
|
11
|
+
module Parser
|
12
|
+
autoload :CommentParser, 'smart_todo/parser/comment_parser'
|
13
|
+
autoload :TodoNode, 'smart_todo/parser/todo_node'
|
14
|
+
autoload :MetadataParser, 'smart_todo/parser/metadata_parser'
|
15
|
+
end
|
16
|
+
|
17
|
+
module Events
|
18
|
+
autoload :Date, 'smart_todo/events/date'
|
19
|
+
autoload :GemRelease, 'smart_todo/events/gem_release'
|
20
|
+
autoload :PullRequestClose, 'smart_todo/events/pull_request_close'
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'smart_todo/parser/metadata_parser'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module SmartTodo
|
8
|
+
# A RuboCop used to restrict the usage of regular TODO comments in code.
|
9
|
+
# This Cop does not run by default. It should be added to the RuboCop host's configuration file.
|
10
|
+
#
|
11
|
+
# @see https://rubocop.readthedocs.io/en/latest/extensions/#loading-extensions
|
12
|
+
class SmartTodoCop < Cop
|
13
|
+
MSG = "Don't write regular TODO comments. Write SmartTodo compatible syntax comments." \
|
14
|
+
"For more info please look at https://github.com/shopify/smart_todo"
|
15
|
+
|
16
|
+
# @param processed_source [RuboCop::ProcessedSource]
|
17
|
+
# @return [void]
|
18
|
+
def investigate(processed_source)
|
19
|
+
processed_source.comments.each do |comment|
|
20
|
+
next unless /^#\sTODO/ =~ comment.text
|
21
|
+
next if smart_todo?(comment.text)
|
22
|
+
|
23
|
+
add_offense(comment)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param comment [String]
|
28
|
+
# @return [true, false]
|
29
|
+
def smart_todo?(comment)
|
30
|
+
metadata = ::SmartTodo::Parser::MetadataParser.parse(comment.gsub(/^#/, ''))
|
31
|
+
|
32
|
+
metadata.events.any?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/shipit.rubygems.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# using the default shipit config
|
data/smart_todo.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "smart_todo/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "smart_todo"
|
9
|
+
spec.version = SmartTodo::VERSION
|
10
|
+
spec.authors = ["Shopify"]
|
11
|
+
spec.email = ["rails@shopify.com"]
|
12
|
+
|
13
|
+
spec.summary = "Enhance todo's comments in your codebase."
|
14
|
+
spec.description = <<~EOM
|
15
|
+
SmartTodo is a tool designed to assign specific users on todo's task
|
16
|
+
written in your codebase and help assignees be reminded when it's time to commit
|
17
|
+
to their todo's.
|
18
|
+
EOM
|
19
|
+
spec.homepage = "https://github.com/shopify/smart_todo"
|
20
|
+
spec.license = "MIT"
|
21
|
+
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
24
|
+
spec.metadata["changelog_uri"] = spec.homepage + "/blob/master/CHANGELOG.md"
|
25
|
+
|
26
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
27
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = ['smart_todo']
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_development_dependency("bundler", "~> 1.17")
|
34
|
+
spec.add_development_dependency("rake", "~> 10.0")
|
35
|
+
spec.add_development_dependency("minitest", "~> 5.0")
|
36
|
+
spec.add_development_dependency("webmock")
|
37
|
+
spec.add_development_dependency("rubocop")
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smart_todo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shopify
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.17'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |
|
84
|
+
SmartTodo is a tool designed to assign specific users on todo's task
|
85
|
+
written in your codebase and help assignees be reminded when it's time to commit
|
86
|
+
to their todo's.
|
87
|
+
email:
|
88
|
+
- rails@shopify.com
|
89
|
+
executables:
|
90
|
+
- smart_todo
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- ".gitignore"
|
95
|
+
- ".rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml"
|
96
|
+
- ".rubocop.yml"
|
97
|
+
- ".shopify-build/VERSION"
|
98
|
+
- ".shopify-build/smart-todo.yml"
|
99
|
+
- CODE_OF_CONDUCT.md
|
100
|
+
- Gemfile
|
101
|
+
- Gemfile.lock
|
102
|
+
- LICENSE.txt
|
103
|
+
- README.md
|
104
|
+
- Rakefile
|
105
|
+
- bin/console
|
106
|
+
- bin/rubocop
|
107
|
+
- bin/setup
|
108
|
+
- dev.yml
|
109
|
+
- exe/smart_todo
|
110
|
+
- lib/smart_todo.rb
|
111
|
+
- lib/smart_todo/cli.rb
|
112
|
+
- lib/smart_todo/dispatcher.rb
|
113
|
+
- lib/smart_todo/events.rb
|
114
|
+
- lib/smart_todo/events/date.rb
|
115
|
+
- lib/smart_todo/events/gem_release.rb
|
116
|
+
- lib/smart_todo/events/pull_request_close.rb
|
117
|
+
- lib/smart_todo/parser/comment_parser.rb
|
118
|
+
- lib/smart_todo/parser/metadata_parser.rb
|
119
|
+
- lib/smart_todo/parser/todo_node.rb
|
120
|
+
- lib/smart_todo/slack_client.rb
|
121
|
+
- lib/smart_todo/version.rb
|
122
|
+
- lib/smart_todo_cop.rb
|
123
|
+
- shipit.rubygems.yml
|
124
|
+
- smart_todo.gemspec
|
125
|
+
homepage: https://github.com/shopify/smart_todo
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
metadata:
|
129
|
+
homepage_uri: https://github.com/shopify/smart_todo
|
130
|
+
source_code_uri: https://github.com/shopify/smart_todo
|
131
|
+
changelog_uri: https://github.com/shopify/smart_todo/blob/master/CHANGELOG.md
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 2.7.6
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: Enhance todo's comments in your codebase.
|
152
|
+
test_files: []
|