brief 0.0.5 → 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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +71 -55
  4. data/README.md +149 -48
  5. data/Rakefile +15 -5
  6. data/bin/brief +15 -28
  7. data/brief.gemspec +17 -11
  8. data/examples/blog/brief.rb +54 -0
  9. data/examples/blog/docs/an-intro-to-brief.html.md +9 -0
  10. data/lib/.DS_Store +0 -0
  11. data/lib/brief/briefcase.rb +78 -0
  12. data/lib/brief/cli/change.rb +14 -0
  13. data/lib/brief/cli/init.rb +66 -0
  14. data/{spec/fixtures/generated/project_overview.json → lib/brief/cli/publish.rb} +0 -0
  15. data/lib/brief/cli/write.rb +0 -0
  16. data/lib/brief/configuration.rb +19 -115
  17. data/lib/brief/core_ext.rb +11 -0
  18. data/lib/brief/document/content_extractor.rb +33 -0
  19. data/lib/brief/document/front_matter.rb +20 -0
  20. data/lib/brief/document/rendering.rb +37 -0
  21. data/lib/brief/document.rb +43 -38
  22. data/lib/brief/document_mapper.rb +158 -0
  23. data/lib/brief/dsl.rb +42 -0
  24. data/lib/brief/model/definition.rb +117 -0
  25. data/lib/brief/model.rb +177 -0
  26. data/lib/brief/repository.rb +57 -0
  27. data/lib/brief/version.rb +1 -7
  28. data/lib/brief.rb +35 -40
  29. data/spec/fixtures/example/brief.rb +27 -0
  30. data/spec/fixtures/example/docs/concept.html.md +5 -0
  31. data/spec/fixtures/example/docs/epic.html.md +19 -0
  32. data/spec/fixtures/example/docs/persona.html.md +5 -0
  33. data/spec/fixtures/example/docs/release.html.md +7 -0
  34. data/spec/fixtures/example/docs/resource.html.md +5 -0
  35. data/spec/fixtures/example/docs/user_story.html.md +24 -0
  36. data/spec/fixtures/example/docs/wireframe.html.md +5 -0
  37. data/spec/fixtures/example/models/epic.rb +16 -0
  38. data/spec/lib/brief/briefcase_spec.rb +27 -0
  39. data/spec/lib/brief/document_spec.rb +14 -22
  40. data/spec/lib/brief/dsl_spec.rb +4 -15
  41. data/spec/lib/brief/model_spec.rb +84 -0
  42. data/spec/lib/brief/repository_spec.rb +60 -0
  43. data/spec/spec_helper.rb +12 -14
  44. data/spec/support/test_helpers.rb +0 -0
  45. data/tasks/brief/release.rake +0 -0
  46. metadata +120 -110
  47. data/.gitignore +0 -1
  48. data/Guardfile +0 -5
  49. data/examples/project_overview.md +0 -23
  50. data/lib/brief/cli/commands/config.rb +0 -40
  51. data/lib/brief/cli/commands/publish.rb +0 -27
  52. data/lib/brief/cli/commands/write.rb +0 -27
  53. data/lib/brief/formatters/base.rb +0 -12
  54. data/lib/brief/formatters/github_milestone_rollup.rb +0 -52
  55. data/lib/brief/git.rb +0 -19
  56. data/lib/brief/github/wiki.rb +0 -9
  57. data/lib/brief/github.rb +0 -141
  58. data/lib/brief/github_client/authentication.rb +0 -32
  59. data/lib/brief/github_client/client.rb +0 -86
  60. data/lib/brief/github_client/commands.rb +0 -5
  61. data/lib/brief/github_client/issue_labels.rb +0 -65
  62. data/lib/brief/github_client/issues.rb +0 -22
  63. data/lib/brief/github_client/milestone_issues.rb +0 -13
  64. data/lib/brief/github_client/organization_activity.rb +0 -9
  65. data/lib/brief/github_client/organization_issues.rb +0 -13
  66. data/lib/brief/github_client/organization_repositories.rb +0 -20
  67. data/lib/brief/github_client/organization_users.rb +0 -9
  68. data/lib/brief/github_client/repository_events.rb +0 -8
  69. data/lib/brief/github_client/repository_issue_events.rb +0 -9
  70. data/lib/brief/github_client/repository_issues.rb +0 -8
  71. data/lib/brief/github_client/repository_labels.rb +0 -18
  72. data/lib/brief/github_client/repository_milestones.rb +0 -9
  73. data/lib/brief/github_client/request.rb +0 -181
  74. data/lib/brief/github_client/request_wrapper.rb +0 -121
  75. data/lib/brief/github_client/response_object.rb +0 -50
  76. data/lib/brief/github_client/single_repository.rb +0 -9
  77. data/lib/brief/github_client/user_activity.rb +0 -16
  78. data/lib/brief/github_client/user_gists.rb +0 -9
  79. data/lib/brief/github_client/user_info.rb +0 -9
  80. data/lib/brief/github_client/user_issues.rb +0 -13
  81. data/lib/brief/github_client/user_organizations.rb +0 -9
  82. data/lib/brief/github_client/user_repositories.rb +0 -9
  83. data/lib/brief/github_client.rb +0 -43
  84. data/lib/brief/handlers/base.rb +0 -62
  85. data/lib/brief/handlers/github_issue.rb +0 -41
  86. data/lib/brief/handlers/github_milestone.rb +0 -37
  87. data/lib/brief/handlers/github_wiki.rb +0 -11
  88. data/lib/brief/line.rb +0 -69
  89. data/lib/brief/parser.rb +0 -354
  90. data/lib/brief/publisher/handler_manager.rb +0 -47
  91. data/lib/brief/publisher.rb +0 -142
  92. data/lib/brief/tree.rb +0 -43
  93. data/lib/core_ext.rb +0 -37
  94. data/spec/fixtures/front_end_tutorial.md +0 -33
  95. data/spec/fixtures/generator_dsl_example.rb +0 -22
  96. data/spec/fixtures/project_overview.md +0 -48
  97. data/spec/fixtures/sample.md +0 -19
  98. data/spec/lib/brief/line_spec.rb +0 -11
  99. data/spec/lib/brief/parser_spec.rb +0 -12
@@ -1,181 +0,0 @@
1
- require 'rubygems'
2
- require 'escape_utils'
3
- require 'uri_template'
4
-
5
- class Brief::GithubClient::Request
6
-
7
- MissingArguments = Class.new(Exception)
8
-
9
- attr_accessor :options, :user, :org, :repo, :params, :headers, :github_token
10
-
11
- class << self
12
- attr_accessor :_required_arguments
13
- end
14
-
15
- def self.requires *args
16
- (self._required_arguments = args).uniq!
17
- end
18
-
19
- def self.required_arguments
20
- Array(self._required_arguments).uniq
21
- end
22
-
23
- def initialize(options={}, &block)
24
- @options = options.with_indifferent_access.dup
25
- @client, @user, @org, @repo, @github_token = options.values_at(:client, :user,:org,:repo,:github_token)
26
- @params = options[:params] || {}
27
- @headers = options[:headers] || {}
28
-
29
- instance_eval(&blk) if block_given?
30
-
31
- assert_valid_arguments!
32
- end
33
-
34
- def required_arguments
35
- Array(self.class._required_arguments)
36
- end
37
-
38
- def with_valid_arguments &blk
39
- instance_eval(&blk) if block_given?
40
- assert_valid_arguments!
41
- self
42
- end
43
-
44
- def assert_valid_arguments!
45
- return true if required_arguments.length > 0
46
-
47
- valid = required_arguments.all? do |arg|
48
- test = false
49
- test = true if !!self.send(arg).present?
50
- test = true if options.has_key?(arg)
51
-
52
- test
53
- end
54
-
55
- raise MissingArguments unless valid
56
- end
57
-
58
- def to_object
59
- req = self
60
-
61
- response_wrapper = lambda do |r|
62
- Brief::GithubClient::ResponseObject.new(r).with_request_object(req)
63
- end
64
-
65
- return object.map(&response_wrapper) if object.is_a?(Array)
66
-
67
- response_wrapper.call(object)
68
- end
69
-
70
- def object
71
- records
72
- end
73
-
74
- def refresh
75
- @request = nil
76
- self
77
- end
78
-
79
- def all
80
- to_object
81
- end
82
-
83
- def create params={}
84
- client.post_request(request_endpoint, params).request.run
85
- end
86
-
87
- def create_object params={}
88
- resp = create(params)
89
- Hashie::Mash.new(JSON.parse(resp.body))
90
- end
91
-
92
- def update record_id, params={}
93
- client.update_request("#{ request_endpoint }/#{ record_id }", params).request.run
94
- end
95
-
96
- def update_object record_id, params={}
97
- resp = update(record_id, params)
98
- Hashie::Mash.new(JSON.parse(resp.body))
99
- end
100
-
101
- def destroy record_id, params={}
102
- client.delete_request("#{ request_endpoint }/#{ record_id }").request.run
103
- end
104
-
105
- def show record_id, params={}
106
- client.get_request("#{ request_endpoint }/#{ record_id }", params).to_object
107
- end
108
-
109
- def client
110
- return @client if @client
111
-
112
- if impersonate_user.present?
113
- @client = Brief::GithubClient::Client.new(user: impersonate_user, headers: headers, github_token: github_token)
114
- end
115
-
116
- @client = Brief.github_client
117
- end
118
-
119
- def records
120
- @records = request.records
121
- end
122
-
123
- def results
124
- records
125
- end
126
-
127
- def result
128
- records
129
- end
130
-
131
- def request_endpoint
132
- options.fetch(:endpoint, endpoint)
133
- end
134
-
135
- def request refresh=false
136
- @request = nil if refresh
137
- @request ||= client.get_request(request_endpoint, params)
138
- end
139
-
140
- def organization_or_user
141
- supplied_org || user
142
- end
143
-
144
- def user_or_organization
145
- supplied_user || supplied_org
146
- end
147
-
148
- def org
149
- organization_or_user
150
- end
151
-
152
- # The idea of 'supplied' means it was provided to the object
153
- # and not calculated in any way. This is used when determining
154
- # the value for the endpoint, in the context of a github user vs github organization
155
- def supplied_org
156
- @org
157
- end
158
-
159
- def supplied_user
160
- @user
161
- end
162
-
163
- def supplied_repo
164
- @repo
165
- end
166
-
167
- protected
168
- def github_token
169
- @github_token || impersonate_user.try(:github_token) || Brief.config.github_token
170
- end
171
-
172
- def endpoint
173
- "users/#{ user }"
174
- end
175
-
176
- def impersonate_user
177
- if defined?(::User) && ::User.respond_to?(:find_by_github_nickname)
178
- @impersonate_user ||= ::User.find_by_github_nickname(user)
179
- end
180
- end
181
- end
@@ -1,121 +0,0 @@
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
@@ -1,50 +0,0 @@
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
@@ -1,9 +0,0 @@
1
- module Brief::GithubClient
2
- class SingleRepository < Request
3
- requires :org, :repo
4
-
5
- def endpoint
6
- "repos/#{ org }/#{ repo }"
7
- end
8
- end
9
- end
@@ -1,16 +0,0 @@
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
@@ -1,9 +0,0 @@
1
- module Brief::GithubClient
2
- class UserGists < Request
3
- requires :user
4
-
5
- def endpoint
6
- "users/#{ user }/gists"
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Brief::GithubClient
2
- class UserInfo < Request
3
- requires :user
4
-
5
- def endpoint
6
- "users/#{ user }"
7
- end
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- module Brief::GithubClient
2
- class UserIssues < Request
3
- requires :user
4
-
5
- def endpoint
6
- "users/#{ user }/issues"
7
- end
8
-
9
- def params
10
- @params.merge(sort:"updated")
11
- end
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- module Brief::GithubClient
2
- class UserOrganizations < Request
3
- requires :user
4
-
5
- def endpoint
6
- "users/#{ user }/orgs"
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Brief::GithubClient
2
- class UserRepositories < Request
3
- requires :user
4
-
5
- def endpoint
6
- "users/#{ user }/repos"
7
- end
8
- end
9
- end
@@ -1,43 +0,0 @@
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'
@@ -1,62 +0,0 @@
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
@@ -1,41 +0,0 @@
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
@@ -1,37 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- module Brief
2
- module Handlers
3
- class GithubWiki < Base
4
- def prepare!
5
- @prepared ||= begin
6
- element
7
- end
8
- end
9
- end
10
- end
11
- end
data/lib/brief/line.rb DELETED
@@ -1,69 +0,0 @@
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
-