brief 0.0.1 → 0.0.2
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 +5 -13
- data/Gemfile +4 -0
- data/Gemfile.lock +81 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +71 -0
- data/Rakefile +11 -0
- data/bin/brief +35 -0
- data/brief-0.0.1.gem +0 -0
- data/brief.gemspec +33 -0
- data/examples/project_overview.md +23 -0
- data/lib/brief/cli/commands/config.rb +40 -0
- data/lib/brief/cli/commands/publish.rb +27 -0
- data/lib/brief/cli/commands/write.rb +26 -0
- data/lib/brief/configuration.rb +134 -0
- data/lib/brief/document.rb +68 -0
- data/lib/brief/dsl.rb +0 -0
- data/lib/brief/formatters/base.rb +12 -0
- data/lib/brief/formatters/github_milestone_rollup.rb +52 -0
- data/lib/brief/git.rb +19 -0
- data/lib/brief/github/wiki.rb +9 -0
- data/lib/brief/github.rb +78 -0
- data/lib/brief/github_client/authentication.rb +32 -0
- data/lib/brief/github_client/client.rb +86 -0
- data/lib/brief/github_client/commands.rb +5 -0
- data/lib/brief/github_client/issue_labels.rb +65 -0
- data/lib/brief/github_client/issues.rb +22 -0
- data/lib/brief/github_client/milestone_issues.rb +13 -0
- data/lib/brief/github_client/organization_activity.rb +9 -0
- data/lib/brief/github_client/organization_issues.rb +13 -0
- data/lib/brief/github_client/organization_repositories.rb +20 -0
- data/lib/brief/github_client/organization_users.rb +9 -0
- data/lib/brief/github_client/repository_events.rb +8 -0
- data/lib/brief/github_client/repository_issue_events.rb +9 -0
- data/lib/brief/github_client/repository_issues.rb +8 -0
- data/lib/brief/github_client/repository_labels.rb +18 -0
- data/lib/brief/github_client/repository_milestones.rb +9 -0
- data/lib/brief/github_client/request.rb +181 -0
- data/lib/brief/github_client/request_wrapper.rb +121 -0
- data/lib/brief/github_client/response_object.rb +50 -0
- data/lib/brief/github_client/single_repository.rb +9 -0
- data/lib/brief/github_client/user_activity.rb +16 -0
- data/lib/brief/github_client/user_gists.rb +9 -0
- data/lib/brief/github_client/user_info.rb +9 -0
- data/lib/brief/github_client/user_issues.rb +13 -0
- data/lib/brief/github_client/user_organizations.rb +9 -0
- data/lib/brief/github_client/user_repositories.rb +9 -0
- data/lib/brief/github_client.rb +43 -0
- data/lib/brief/handlers/base.rb +62 -0
- data/lib/brief/handlers/github_issue.rb +41 -0
- data/lib/brief/handlers/github_milestone.rb +37 -0
- data/lib/brief/handlers/github_wiki.rb +11 -0
- data/lib/brief/line.rb +69 -0
- data/lib/brief/parser.rb +354 -0
- data/lib/brief/publisher/handler_manager.rb +47 -0
- data/lib/brief/publisher.rb +142 -0
- data/lib/brief/tree.rb +42 -0
- data/lib/brief/version.rb +9 -0
- data/lib/brief.rb +56 -0
- data/lib/core_ext.rb +37 -0
- data/spec/fixtures/front_end_tutorial.md +33 -0
- data/spec/fixtures/generated/project_overview.json +0 -0
- data/spec/fixtures/generator_dsl_example.rb +22 -0
- data/spec/fixtures/project_overview.md +48 -0
- data/spec/fixtures/sample.md +19 -0
- data/spec/lib/brief/document_spec.rb +35 -0
- data/spec/lib/brief/dsl_spec.rb +21 -0
- data/spec/lib/brief/line_spec.rb +11 -0
- data/spec/lib/brief/parser_spec.rb +12 -0
- data/spec/spec_helper.rb +25 -0
- metadata +231 -9
@@ -0,0 +1,121 @@
|
|
1
|
+
module Brief::GithubClient
|
2
|
+
|
3
|
+
class RequestWrapper
|
4
|
+
attr_accessor :request,:headers,:params,:type, :method
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :request_cache, :response_cache
|
8
|
+
end
|
9
|
+
|
10
|
+
self.request_cache ||= Brief::GithubClient.request_cache
|
11
|
+
self.response_cache ||= Brief::GithubClient.response_cache
|
12
|
+
|
13
|
+
def initialize(type,params,headers)
|
14
|
+
@type = type
|
15
|
+
@params = params
|
16
|
+
@headers = headers
|
17
|
+
@method = :get
|
18
|
+
|
19
|
+
@cache_key = Digest::MD5.hexdigest([params.to_json, type].to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
def url
|
23
|
+
"https://api.github.com/#{ type }"
|
24
|
+
end
|
25
|
+
|
26
|
+
def request
|
27
|
+
if method == :get
|
28
|
+
@request = Typhoeus::Request.new url,
|
29
|
+
method: method,
|
30
|
+
headers: request_headers,
|
31
|
+
params: params
|
32
|
+
else
|
33
|
+
@request = Typhoeus::Request.new url,
|
34
|
+
method: method,
|
35
|
+
headers: request_headers,
|
36
|
+
body: JSON.generate(params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get
|
41
|
+
@method = :get
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
@method = :patch
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def post
|
51
|
+
@method = :post
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def create
|
56
|
+
@method = :post
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete
|
61
|
+
@method = :delete
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def request_headers
|
66
|
+
if method == :get && cached_etag.present? && cached_etag.length > 1
|
67
|
+
if Brief::GithubClient.enable_caching
|
68
|
+
@headers["If-None-Match"] = cached_etag.split('|').first
|
69
|
+
@headers["If-Modified-Since"] = cached_etag.split('|').last
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@headers
|
74
|
+
end
|
75
|
+
|
76
|
+
def cached_etag
|
77
|
+
Brief::GithubClient.enable_caching ? self.class.request_cache[cache_key] : nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def cache_key
|
81
|
+
@cache_key
|
82
|
+
end
|
83
|
+
|
84
|
+
def cached?
|
85
|
+
response.headers.try(:[],"Status") == "304 Not Modified"
|
86
|
+
end
|
87
|
+
|
88
|
+
def response
|
89
|
+
return @response if @response
|
90
|
+
|
91
|
+
@response = request.run
|
92
|
+
|
93
|
+
if Brief::GithubClient.enable_caching && response.headers.try(:[],"Status") == "200 OK"
|
94
|
+
self.class.request_cache[cache_key] = "#{response.headers.try(:[],"Etag")}|#{ response.headers.try(:[],"Last-Modified") }"
|
95
|
+
self.class.response_cache[cache_key] = response.body
|
96
|
+
end
|
97
|
+
|
98
|
+
@response
|
99
|
+
end
|
100
|
+
|
101
|
+
def result
|
102
|
+
@result ||= JSON.parse(response_body)
|
103
|
+
end
|
104
|
+
|
105
|
+
def response_body
|
106
|
+
return response.body unless Brief::GithubClient.enable_caching
|
107
|
+
|
108
|
+
self.class.response_cache.fetch(cache_key) do
|
109
|
+
response.body
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def records
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_object
|
118
|
+
Hashie::Mash.new(result)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Brief::GithubClient
|
2
|
+
class ResponseObject < Hashie::Mash
|
3
|
+
|
4
|
+
def url_fields
|
5
|
+
keys.grep(/_url/).inject({}) do |memo,field|
|
6
|
+
memo[field] = self.send(field)
|
7
|
+
memo
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def with_request_class obj
|
12
|
+
@request_class = obj if obj
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_request_object obj
|
17
|
+
@request_object = obj if obj
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def request_object
|
22
|
+
@request_object
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_class
|
26
|
+
@request_class || Brief::GithubClient::Request
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch(relationship, params={})
|
30
|
+
if endpoint_for(relationship)
|
31
|
+
endpoint_url = endpoint_for(relationship)
|
32
|
+
tmpl = URITemplate.new(endpoint_url)
|
33
|
+
request_class.new(client: request_object.client, endpoint: tmpl.expand(params))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def endpoint_for(relationship)
|
38
|
+
url = url_for(relationship)
|
39
|
+
url && url.gsub(%r{https://api.github.com/},'')
|
40
|
+
end
|
41
|
+
|
42
|
+
def url_for(relationship)
|
43
|
+
field ="#{ relationship }_url"
|
44
|
+
|
45
|
+
if has_key?(field)
|
46
|
+
send(field)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Brief::GithubClient
|
2
|
+
class UserActivity < Request
|
3
|
+
requires :user
|
4
|
+
|
5
|
+
def endpoint
|
6
|
+
"users/#{user}/events"
|
7
|
+
end
|
8
|
+
|
9
|
+
def organization_repos
|
10
|
+
all.select do |item|
|
11
|
+
item.repo && item.repo.name.try(:match,org) rescue false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Brief::GithubClient
|
2
|
+
def self.default_organization
|
3
|
+
Brief.profile.github_organization
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.default_github_token
|
7
|
+
Brief.profile.github_token
|
8
|
+
end
|
9
|
+
|
10
|
+
# Brief.github_client is useful for backend apps where there is a Brief configuration profile
|
11
|
+
Brief.define_singleton_method(:github_client) do
|
12
|
+
Brief::GithubClient::Client.new(github_token: Brief.profile.github_token)
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
attr_accessor :request_cache,
|
17
|
+
:response_cache,
|
18
|
+
:enable_caching
|
19
|
+
end
|
20
|
+
|
21
|
+
self.request_cache ||= {}
|
22
|
+
self.response_cache ||= {}
|
23
|
+
self.enable_caching = false
|
24
|
+
|
25
|
+
def self.clear_caches!
|
26
|
+
self.request_cache = {}
|
27
|
+
self.response_cache = {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'brief/github_client/authentication'
|
32
|
+
require 'brief/github_client/client'
|
33
|
+
require 'brief/github_client/request'
|
34
|
+
require 'brief/github_client/request_wrapper'
|
35
|
+
require 'brief/github_client/response_object'
|
36
|
+
require 'brief/github_client/commands'
|
37
|
+
require 'brief/github_client/issues'
|
38
|
+
require 'brief/github_client/issue_labels'
|
39
|
+
require 'brief/github_client/repository_issues'
|
40
|
+
require 'brief/github_client/repository_milestones'
|
41
|
+
require 'brief/github_client/repository_labels'
|
42
|
+
require 'brief/github_client/milestone_issues'
|
43
|
+
require 'brief/github_client/user_issues'
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Brief
|
2
|
+
module Handlers
|
3
|
+
class Base
|
4
|
+
attr_accessor :element, :prepared
|
5
|
+
|
6
|
+
def initialize(element)
|
7
|
+
@element = element
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing meth, *args, &block
|
11
|
+
if element.respond_to?(meth)
|
12
|
+
return element.send(meth, *args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def content
|
19
|
+
element.content
|
20
|
+
end
|
21
|
+
|
22
|
+
def document
|
23
|
+
get_manager.try :document
|
24
|
+
end
|
25
|
+
|
26
|
+
def document_settings
|
27
|
+
document.try(:settings)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_manager &block
|
31
|
+
if block_given?
|
32
|
+
@get_manager = block
|
33
|
+
end
|
34
|
+
|
35
|
+
@get_manager && @get_manager.call()
|
36
|
+
end
|
37
|
+
|
38
|
+
def parent &block
|
39
|
+
if block_given?
|
40
|
+
@find_parent_block = block
|
41
|
+
end
|
42
|
+
|
43
|
+
@find_parent_block && @find_parent_block.call(element.parent_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Your handler should implement this method, the goal is to transform the
|
47
|
+
# element we are passed into an object that is suitable for whatever integration
|
48
|
+
# you have planned for it. For example, preparing the necessary attributes for
|
49
|
+
# a submission to github issues or milestones
|
50
|
+
def prepare!
|
51
|
+
@prepared ||= begin
|
52
|
+
element
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Do whatever you want to do with the prepared element
|
57
|
+
def handle!
|
58
|
+
prepare!
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Brief
|
2
|
+
module Handlers
|
3
|
+
class GithubIssue < Base
|
4
|
+
def prepare!
|
5
|
+
@prepared ||= begin
|
6
|
+
if github_api_issue.present?
|
7
|
+
element.issue_url = github_api_issue.url
|
8
|
+
element.issue_number = github_api_issue.number
|
9
|
+
else
|
10
|
+
element.issue_url = create_in_github_api.url
|
11
|
+
element.issue_number = github_api_issue.number
|
12
|
+
end
|
13
|
+
|
14
|
+
element
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_in_github_api
|
19
|
+
issues_api.create_object(body: body, title: title, milestone: milestone)
|
20
|
+
end
|
21
|
+
|
22
|
+
def body
|
23
|
+
element.content
|
24
|
+
end
|
25
|
+
|
26
|
+
def milestone
|
27
|
+
parent && parent.milestone_number
|
28
|
+
end
|
29
|
+
|
30
|
+
def issues_api refresh=false
|
31
|
+
Brief.repository_issues.tap do |api|
|
32
|
+
refresh ? api.refresh : api
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def github_api_issue
|
37
|
+
issues_api(true).all.detect {|issue| issue.title == title }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Brief
|
2
|
+
module Handlers
|
3
|
+
class GithubMilestone < Base
|
4
|
+
def prepare!
|
5
|
+
@prepared ||= begin
|
6
|
+
if github_api_milestone.present?
|
7
|
+
element.milestone_url = github_api_milestone.url
|
8
|
+
element.milestone_number = github_api_milestone.number
|
9
|
+
else
|
10
|
+
element.milestone_url = create_in_github_api.url
|
11
|
+
element.milestone_number = github_api_milestone.number
|
12
|
+
end
|
13
|
+
|
14
|
+
element
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_in_github_api
|
19
|
+
@github_api_milestone ||= milestones_api.create_object(body: body, title: title)
|
20
|
+
end
|
21
|
+
|
22
|
+
def body
|
23
|
+
document.parser.content_lines_under(title).reject(&:blank?).join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def milestones_api refresh=false
|
27
|
+
Brief.repository_milestones.tap do |api|
|
28
|
+
refresh ? api.refresh : api
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def github_api_milestone
|
33
|
+
@github_api_milestone ||= milestones_api(true).all.detect {|milestone| milestone.title == element.title }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/brief/line.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Brief
|
2
|
+
class Line
|
3
|
+
attr_reader :_content,
|
4
|
+
:number,
|
5
|
+
:code
|
6
|
+
|
7
|
+
attr_accessor :raw
|
8
|
+
|
9
|
+
HeadingRegex = /^#+\s*/
|
10
|
+
CodeBlockRegex = /^\s*```/
|
11
|
+
|
12
|
+
def initialize(content, number, code=false)
|
13
|
+
@_content = content
|
14
|
+
@number = number + 1
|
15
|
+
@code = code
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
content
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
case
|
24
|
+
when code?
|
25
|
+
"content"
|
26
|
+
when _content.match(HeadingRegex)
|
27
|
+
"heading"
|
28
|
+
when _content.match(CodeBlockRegex)
|
29
|
+
"code_block_marker"
|
30
|
+
else
|
31
|
+
"content"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def content
|
36
|
+
_content.gsub(HeadingRegex, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def raw
|
40
|
+
@raw || _content
|
41
|
+
end
|
42
|
+
|
43
|
+
def heading?
|
44
|
+
!code? && type == "heading"
|
45
|
+
end
|
46
|
+
|
47
|
+
def level
|
48
|
+
_content.match(HeadingRegex).to_s.count('#')
|
49
|
+
end
|
50
|
+
|
51
|
+
def sort_index
|
52
|
+
[level, number]
|
53
|
+
end
|
54
|
+
|
55
|
+
def line_number
|
56
|
+
number
|
57
|
+
end
|
58
|
+
|
59
|
+
def content?
|
60
|
+
type == "content" || type == "code_block_marker"
|
61
|
+
end
|
62
|
+
|
63
|
+
def code?
|
64
|
+
!!@code
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|