aweplug 1.0.0.a2
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.
- data/.gitignore +23 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.adoc +3 -0
- data/README.md +29 -0
- data/Rakefile +51 -0
- data/aweplug.gemspec +29 -0
- data/lib/aweplug/extensions/identities.rb +187 -0
- data/lib/aweplug/extensions/identity/confluence.rb +107 -0
- data/lib/aweplug/extensions/identity/github.rb +230 -0
- data/lib/aweplug/extensions/identity/gravatar.rb +117 -0
- data/lib/aweplug/extensions/identity/jbosscommunity.rb +35 -0
- data/lib/aweplug/extensions/kramdown_quickstart.rb +41 -0
- data/lib/aweplug/extensions/sections.rb +30 -0
- data/lib/aweplug/helpers/.gitkeep +0 -0
- data/lib/aweplug/helpers/git_commit_metadata.rb +23 -0
- data/lib/aweplug/helpers/kramdown_metadata.rb +58 -0
- data/lib/aweplug/transformers/.gitkeep +0 -0
- data/lib/aweplug/version.rb +4 -0
- data/lib/aweplug.rb +5 -0
- data/spec/aweplug/extensions/identity/collector_spec.rb +24 -0
- data/spec/aweplug/extensions/identity/github_spec.rb +7 -0
- data/spec/aweplug/extensions/identity/storage_spec.rb +24 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/aweplug/extensions/identity/crawler_examples.rb +13 -0
- metadata +160 -0
data/.gitignore
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
.bundle
|
|
4
|
+
.config
|
|
5
|
+
coverage
|
|
6
|
+
InstalledFiles
|
|
7
|
+
lib/bundler/man
|
|
8
|
+
pkg
|
|
9
|
+
rdoc
|
|
10
|
+
spec/reports
|
|
11
|
+
test/tmp
|
|
12
|
+
test/version_tmp
|
|
13
|
+
tmp
|
|
14
|
+
Gemfile.lock
|
|
15
|
+
|
|
16
|
+
# YARD artifacts
|
|
17
|
+
.yardoc
|
|
18
|
+
_yardoc
|
|
19
|
+
doc/
|
|
20
|
+
.bundle
|
|
21
|
+
vendor/bundle
|
|
22
|
+
vendor/cache
|
|
23
|
+
pkg
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 LightGuard
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.adoc
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Aweplug
|
|
2
|
+
|
|
3
|
+
TODO: Write a gem description
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'aweplug'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install aweplug
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
TODO: Write usage instructions here
|
|
22
|
+
|
|
23
|
+
## Contributing
|
|
24
|
+
|
|
25
|
+
1. Fork it
|
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require 'rspec/core/rake_task'
|
|
3
|
+
require 'aweplug/version'
|
|
4
|
+
require 'guard'
|
|
5
|
+
|
|
6
|
+
GEMFILE = "aweplug-#{Aweplug::VERSION}.gem"
|
|
7
|
+
|
|
8
|
+
task :default => :build
|
|
9
|
+
|
|
10
|
+
desc "Run all tests and build the gem"
|
|
11
|
+
task :build => 'test:spec' do
|
|
12
|
+
system "gem build aweplug.gemspec"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc "Build and install the gem locally"
|
|
16
|
+
task :install => :build do
|
|
17
|
+
system "gem install -l -f #{GEMFILE}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
namespace :release do
|
|
21
|
+
desc "Release the gem to rubygems"
|
|
22
|
+
task :push => [ :build, :tag ] do
|
|
23
|
+
system "gem push #{GEMFILE}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc "Create tag #{Aweplug::VERSION} in git"
|
|
27
|
+
task :tag do
|
|
28
|
+
system "git tag #{Aweplug::VERSION}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
namespace :test do
|
|
33
|
+
if !defined?(RSpec)
|
|
34
|
+
puts "spec targets require RSpec"
|
|
35
|
+
else
|
|
36
|
+
desc "Run all specifications"
|
|
37
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
38
|
+
t.pattern = 'spec/**/*_spec.rb'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc "Start Guard to listen for changes and run specs"
|
|
43
|
+
task :guard do
|
|
44
|
+
Guard.start(:guardfile => 'Guardfile')
|
|
45
|
+
Guard.run_all
|
|
46
|
+
while ::Guard.running do
|
|
47
|
+
sleep 0.5
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
data/aweplug.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'aweplug/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |gem|
|
|
7
|
+
gem.name = "aweplug"
|
|
8
|
+
gem.version = Aweplug::VERSION
|
|
9
|
+
gem.authors = ["LightGuard"]
|
|
10
|
+
gem.email = ["lightguard.jp@gmail.com"]
|
|
11
|
+
gem.description = %q{A set of Awestruct extensions for building a project website}
|
|
12
|
+
gem.summary = %q{This set of Awestruct extensions includes helpful tools,
|
|
13
|
+
extensions and helpers for building a website using Awestruct.
|
|
14
|
+
It includes extensions for accessing Github, JIRA, managing identities and others.}
|
|
15
|
+
gem.homepage = "https://github.com/awestruct/aweplug"
|
|
16
|
+
|
|
17
|
+
gem.files = `git ls-files`.split($/)
|
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
20
|
+
gem.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
#gem.add_dependency 'awestruct', '>= 0.5.1'
|
|
23
|
+
gem.add_dependency 'octokit', '>= 1.24.0'
|
|
24
|
+
gem.add_dependency 'faraday', '>= 0.8.7'
|
|
25
|
+
gem.add_dependency 'faraday_middleware', '>= 0.9.0'
|
|
26
|
+
|
|
27
|
+
gem.add_development_dependency 'guard-rspec', '~> 3.0.0'
|
|
28
|
+
gem.add_development_dependency 'rake', '~> 10.0.4'
|
|
29
|
+
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'aweplug/extensions/restclient_extensions'
|
|
3
|
+
require 'aweplug/extensions/identity/github'
|
|
4
|
+
require 'aweplug/extensions/identity/gravatar'
|
|
5
|
+
require 'aweplug/extensions/identity/confluence'
|
|
6
|
+
require 'aweplug/extensions/identity/jbosscommunity'
|
|
7
|
+
|
|
8
|
+
module Aweplug
|
|
9
|
+
module Extensions
|
|
10
|
+
module Identities
|
|
11
|
+
# QUESTION should we call this Initializer or Loader instead?
|
|
12
|
+
class Storage
|
|
13
|
+
def initialize(opts = {})
|
|
14
|
+
@use_data_cache = opts[:use_data_cache] || true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Internal: Awestruct calls this method during site generation.
|
|
18
|
+
# Iterates through all the different identity in the site and finds
|
|
19
|
+
# information about them.
|
|
20
|
+
#
|
|
21
|
+
# site - This must be the site object provided by awestruct
|
|
22
|
+
#
|
|
23
|
+
# Returns nothing
|
|
24
|
+
def execute(site)
|
|
25
|
+
data_file = File.join(site.tmp_dir, 'datacache', 'identity.yml')
|
|
26
|
+
loaded = false
|
|
27
|
+
identities = []
|
|
28
|
+
if @use_data_cache and File.exist? data_file
|
|
29
|
+
identities = YAML.load_file data_file
|
|
30
|
+
loaded = true
|
|
31
|
+
else
|
|
32
|
+
if site.identities
|
|
33
|
+
identities = site.identities.map { |i| OpenStruct.new i }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
identities.extend(Locators)
|
|
37
|
+
identities.loaded = loaded
|
|
38
|
+
site.identities = identities
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module Locators
|
|
42
|
+
attr_accessor :loaded
|
|
43
|
+
|
|
44
|
+
def lookup(username, create = false)
|
|
45
|
+
identity = self.find { |e| username.eql? e.username } ||
|
|
46
|
+
self.find { |e| username.eql? e.jboss_username }
|
|
47
|
+
if create and identity.nil?
|
|
48
|
+
identity = OpenStruct.new({:username => username})
|
|
49
|
+
if block_given?
|
|
50
|
+
yield identity
|
|
51
|
+
end
|
|
52
|
+
self << identity
|
|
53
|
+
end
|
|
54
|
+
identity
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def lookup_by_name(name, create = false)
|
|
58
|
+
search = name.downcase
|
|
59
|
+
identity = self.find { |e| search.eql? e.name.to_s.downcase }
|
|
60
|
+
if create and identity.nil?
|
|
61
|
+
identity = OpenStruct.new({:name => name})
|
|
62
|
+
if block_given?
|
|
63
|
+
yield identity
|
|
64
|
+
end
|
|
65
|
+
self << identity
|
|
66
|
+
end
|
|
67
|
+
identity
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def lookup_by_contributor(contributor)
|
|
71
|
+
identity = self.find { |e| e.contributor and e.contributor.emails and e.contributor.emails.include? contributor.email }
|
|
72
|
+
if identity.nil?
|
|
73
|
+
# Indication that we have a mismatched account
|
|
74
|
+
puts "Could not find contributor with e-mail " + contributor.email
|
|
75
|
+
end
|
|
76
|
+
identity
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def lookup_by_email(email, create = false)
|
|
80
|
+
identity = self.find { |e| email.eql? e.email or !e.emails.nil? and e.emails.include? email }
|
|
81
|
+
if create and identity.nil?
|
|
82
|
+
identity = OpenStruct.new({:email => email})
|
|
83
|
+
if block_given?
|
|
84
|
+
yield identity
|
|
85
|
+
end
|
|
86
|
+
self << identity
|
|
87
|
+
end
|
|
88
|
+
identity
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def lookup_by_github_id(github_id, create = false)
|
|
92
|
+
identity = self.find { |e| github_id.eql? e.github_id }
|
|
93
|
+
if create and identity.nil?
|
|
94
|
+
identity = OpenStruct.new({:github_id => github_id})
|
|
95
|
+
if block_given?
|
|
96
|
+
yield identity
|
|
97
|
+
end
|
|
98
|
+
self << identity
|
|
99
|
+
end
|
|
100
|
+
identity
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def lookup_by_twitter_username(username)
|
|
104
|
+
self.find { |e| !e.twitter.nil? and username.eql? e.twitter.username }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def locate(*query)
|
|
108
|
+
query.map! { |e| e.downcase }
|
|
109
|
+
self.find { |e| not ([e.username, e.name.to_s.downcase, e.email] & query).empty? }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def core_team()
|
|
113
|
+
self.select { |e| e.core }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def contributors()
|
|
117
|
+
self.select { |e| e.contributor }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def speakers()
|
|
121
|
+
self.select { |e| e.speaker }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def translators()
|
|
125
|
+
self.select { |e| e.translator }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
module IdentityHelper
|
|
131
|
+
# SEMI-HACK this should received contributions from crawlers
|
|
132
|
+
def url
|
|
133
|
+
self.jbosscommunity ? self.jbosscommunity.profile_url : self.github.profile_url
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# TODO support for CSS class, or just attributes in general
|
|
137
|
+
def to_link
|
|
138
|
+
"<a href=\"#{self.url}\">#{self.name}</a>"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def to_s
|
|
142
|
+
self.name
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class Collect
|
|
147
|
+
def initialize(*collectors)
|
|
148
|
+
@collectors = collectors
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def execute(site)
|
|
152
|
+
if !site.identities.loaded
|
|
153
|
+
@collectors.each do |c|
|
|
154
|
+
c.collect(site.identities)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
class Crawl
|
|
161
|
+
def initialize(*crawlers)
|
|
162
|
+
@crawlers = crawlers
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def execute(site)
|
|
166
|
+
site.identities.each do |i|
|
|
167
|
+
@crawlers.each do |c|
|
|
168
|
+
c.crawl(i) if !site.identities.loaded
|
|
169
|
+
i.extend(IdentityHelper)
|
|
170
|
+
c.enhance(i) if c.respond_to? 'enhance'
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
class Cache
|
|
177
|
+
def execute(site)
|
|
178
|
+
data_file = File.join(site.tmp_dir, 'datacache', 'identity.yml')
|
|
179
|
+
FileUtils.mkdir_p File.dirname data_file
|
|
180
|
+
File.open(data_file, 'w') do |out|
|
|
181
|
+
YAML.dump site.identities, out
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module Aweplug
|
|
4
|
+
module Extensions
|
|
5
|
+
module Identity
|
|
6
|
+
module Confluence
|
|
7
|
+
class Crawler
|
|
8
|
+
SESSION_PATH = '/rest/prototype/1/session'
|
|
9
|
+
SEARCH_PATH = '/rest/prototype/1/search/user'
|
|
10
|
+
SEARCH_PARAM = 'query'
|
|
11
|
+
|
|
12
|
+
# Public: Initialize a Crawler
|
|
13
|
+
#
|
|
14
|
+
# base_url - The String of the base confluence url, no trailing slash
|
|
15
|
+
# opts[:assign_to] - The String OpenStruct keys to send the data
|
|
16
|
+
# opts[:identity_search_keys] - The String OpenStruct keys to use to locate the search query
|
|
17
|
+
# opts[:assign_username_to] - The String OpenStruct key to which to assign the username
|
|
18
|
+
# opts[:auth_file] - The File containing the authentication credentials for secure requests
|
|
19
|
+
def initialize(base_url, opts = {})
|
|
20
|
+
@base_url = base_url
|
|
21
|
+
@identity_search_keys = opts[:identity_search_keys] || ['name']
|
|
22
|
+
@assign_to = opts[:assign_to] || 'confluence'
|
|
23
|
+
@assign_username_to = opts[:assign_username_to]
|
|
24
|
+
@auth_file = opts[:auth_file]
|
|
25
|
+
@session_cookie = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def crawl(identity)
|
|
29
|
+
search = nil
|
|
30
|
+
queries = []
|
|
31
|
+
data = nil
|
|
32
|
+
@identity_search_keys.each do |k|
|
|
33
|
+
search = identity.send(k)
|
|
34
|
+
next if search.nil?
|
|
35
|
+
# lowercase and remove middle names (shouldn't affect usernames)
|
|
36
|
+
search = search.downcase.gsub(/^([^ ]+ ?).*?([^ ]+)$/, '\1\2')
|
|
37
|
+
# don't search on same string twice
|
|
38
|
+
next if queries.include? search
|
|
39
|
+
queries << search
|
|
40
|
+
cleansed_query = search.gsub(' ', '-')
|
|
41
|
+
url = File.join(@base_url, SEARCH_PATH) + '?query=' + URI.encode(search)
|
|
42
|
+
data = RestClient.get(url, :cache_key => "confluence/query-#{cleansed_query}.json", :accept => 'application/json')
|
|
43
|
+
if data['totalSize'].to_i == 0
|
|
44
|
+
#puts "No results, advancing confluence user crawler to next query string for #{search}"
|
|
45
|
+
data = nil
|
|
46
|
+
#elsif data['totalSize'] > 1
|
|
47
|
+
# puts "Too many results, skipping confluence user crawler for #{search}."
|
|
48
|
+
# data = nil
|
|
49
|
+
else
|
|
50
|
+
break
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if data.nil?
|
|
55
|
+
if queries.empty?
|
|
56
|
+
puts "No property found to search, skipping confluence user crawler for #{identity.name}"
|
|
57
|
+
else
|
|
58
|
+
puts "No results, skipping confluence user crawler for #{queries.join ' / '}"
|
|
59
|
+
end
|
|
60
|
+
return
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
user = data['result'].first
|
|
64
|
+
username = user['username']
|
|
65
|
+
url = user['link'].select{|l| l['href'].end_with? "~#{username}" }.first['href']
|
|
66
|
+
identity.send(@assign_to + '=', OpenStruct.new({:username => username, :profile_url => url}))
|
|
67
|
+
if !@assign_username_to.nil?
|
|
68
|
+
identity.send(@assign_username_to + '=', username)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
get_session_cookie()
|
|
72
|
+
if @session_cookie
|
|
73
|
+
profile = RestClient.get(url, :cache_key => "confluence/user-#{username}.html", :cookie => @session_cookie)
|
|
74
|
+
if profile.match(/ id="email".*?>(.+?)</)
|
|
75
|
+
replace = {' dot ' => '.', ' at ' => '@'}
|
|
76
|
+
email = $1.gsub(/ (dot|at) /) {|m| replace[m]}
|
|
77
|
+
identity.email = email if identity.email.nil?
|
|
78
|
+
identity.emails ||= []
|
|
79
|
+
identity.emails |= [identity.email, email]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def get_session_cookie()
|
|
86
|
+
if @session_cookie.nil?
|
|
87
|
+
@session_cookie = false
|
|
88
|
+
credentials = nil
|
|
89
|
+
if !@auth_file.nil?
|
|
90
|
+
if File.exist? @auth_file
|
|
91
|
+
credentials = File.read(@auth_file)
|
|
92
|
+
elsif Pathname.new(@auth_file).relative? and File.exist? File.join(ENV['HOME'], @auth_file)
|
|
93
|
+
credentials = File.read(File.join(ENV['HOME'], @auth_file))
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
if !credentials.nil?
|
|
97
|
+
url = @base_url.gsub(/^(https?:\/\/)/, '\1' + credentials.chomp + '@') + SESSION_PATH
|
|
98
|
+
response = RestClient.head(url)
|
|
99
|
+
@session_cookie = response.headers[:set_cookie].first.split(';').first
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
module Aweplug
|
|
2
|
+
module Extensions
|
|
3
|
+
module Identity
|
|
4
|
+
module GitHub
|
|
5
|
+
CONTRIBUTORS_URL_TEMPLATE = 'https://api.github.com/repos/%s/%s/contributors'
|
|
6
|
+
TEAM_MEMBERS_URL_TEMPLATE = 'https://api.github.com/teams/%s/members'
|
|
7
|
+
USER_URL_TEMPLATE = 'https://api.github.com/users/%s'
|
|
8
|
+
|
|
9
|
+
# It appears that all github users have a gravatar_id
|
|
10
|
+
AVATAR_URL_TEMPLATE = 'http://gravatar.com/avatar/%s?s=%i'
|
|
11
|
+
# TODO make the default avatar configurable
|
|
12
|
+
FALLBACK_AVATAR_URL_TEMPLATE = 'https://community.jboss.org/people/sbs-default-avatar/avatar/%i.png'
|
|
13
|
+
module IdentityHelper
|
|
14
|
+
def avatar_url(size = 48)
|
|
15
|
+
if !self.gravatar_id.nil?
|
|
16
|
+
AVATAR_URL_TEMPLATE % [self.gravatar_id, size]
|
|
17
|
+
else
|
|
18
|
+
FALLBACK_URL_TEMPLATE % size
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Collector
|
|
24
|
+
|
|
25
|
+
def initialize(opts = {})
|
|
26
|
+
@repositories = []
|
|
27
|
+
@match_filters = []
|
|
28
|
+
@teams = opts[:teams]
|
|
29
|
+
@auth_file = opts[:auth_file]
|
|
30
|
+
@credentials = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def add_repository(repository)
|
|
34
|
+
@repositories << repository
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_match_filter(match_filter)
|
|
38
|
+
@match_filters << match_filter
|
|
39
|
+
#File.open('/tmp/committers.yml', 'w') do |out|
|
|
40
|
+
# YAML.dump(match_filter, out)
|
|
41
|
+
#end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def collect(identities)
|
|
45
|
+
visited = []
|
|
46
|
+
@repositories.each do |r|
|
|
47
|
+
url = CONTRIBUTORS_URL_TEMPLATE % [r.owner, r.path]
|
|
48
|
+
contributors = RestClient.get url, :accept => 'application/json'
|
|
49
|
+
contributors.each do |acct|
|
|
50
|
+
github_id = acct['login'].downcase
|
|
51
|
+
author = nil
|
|
52
|
+
@match_filters.each do |filter|
|
|
53
|
+
author = filter.values.find { |candidate| candidate.github_id.eql? github_id }
|
|
54
|
+
break unless author.nil?
|
|
55
|
+
end
|
|
56
|
+
if author.nil?
|
|
57
|
+
#puts "Skipping non-Arquillian contributor #{github_id} in repository #{r.owner}/#{r.path}"
|
|
58
|
+
next
|
|
59
|
+
end
|
|
60
|
+
identity = identities.lookup_by_github_id(github_id, true)
|
|
61
|
+
github_acct_to_identity(acct, author, identity)
|
|
62
|
+
visited << github_id
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# github doesn't keep perfect records of contributors, so handle those omitted contributors
|
|
67
|
+
@match_filters.each do |filter|
|
|
68
|
+
filter.values.select { |author| !author.github_id.nil? and !visited.include? author.github_id }.each do |author|
|
|
69
|
+
github_id = author.github_id
|
|
70
|
+
puts "Manually adding #{author.name} (#{github_id}) as a contributor"
|
|
71
|
+
url = USER_URL_TEMPLATE % [github_id]
|
|
72
|
+
user = RestClient.get url, :accept => 'application/json'
|
|
73
|
+
identity = identities.lookup_by_github_id(github_id, true)
|
|
74
|
+
github_acct_to_identity(user, author, identity)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if !@teams.nil?
|
|
79
|
+
get_credentials()
|
|
80
|
+
if @credentials
|
|
81
|
+
@teams.each do |team|
|
|
82
|
+
url = TEAM_MEMBERS_URL_TEMPLATE % team[:id]
|
|
83
|
+
url = url.gsub(/^(https?:\/\/)/, '\1' + @credentials.chomp + '@')
|
|
84
|
+
members = RestClient.get(url, :accept => 'application/json')
|
|
85
|
+
members.each do |m|
|
|
86
|
+
github_id = m['login']
|
|
87
|
+
identity = identities.lookup_by_github_id(github_id)
|
|
88
|
+
# identity should not be null, mostly for testing
|
|
89
|
+
if !identity.nil?
|
|
90
|
+
identity.send(team[:name] + '=', true)
|
|
91
|
+
identity.teams = [] if identity.teams.nil?
|
|
92
|
+
identity.teams << team[:name]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def github_acct_to_identity(acct, author, identity)
|
|
101
|
+
# setup if first visit
|
|
102
|
+
if identity.github.nil? or identity.github.contributions.nil?
|
|
103
|
+
identity.github = OpenStruct.new if identity.github.nil?
|
|
104
|
+
identity.github.contributions = acct.has_key?('contributions') ? acct['contributions'] : 0
|
|
105
|
+
identity.github_url = acct['url'].downcase
|
|
106
|
+
identity.gravatar_id = acct['gravatar_id']
|
|
107
|
+
# author contains the commits we counted from analyzing the repositories
|
|
108
|
+
identity.contributor = author
|
|
109
|
+
identity.email = author.emails.first if identity.email.nil?
|
|
110
|
+
identity.emails ||= []
|
|
111
|
+
identity.emails |= [identity.email, author.emails.first]
|
|
112
|
+
# alias for convenience
|
|
113
|
+
identity.commits = author.commits
|
|
114
|
+
# assume they want their commit name as the preferred name (unless it's an email)
|
|
115
|
+
if identity.name.nil? and author.name.index('@').nil?
|
|
116
|
+
if !author.name.index(' ').nil?
|
|
117
|
+
# FIXME this could be made into a smarter utility function
|
|
118
|
+
identity.name = author.name.split(' ').map { |n| n.capitalize }.join(' ')
|
|
119
|
+
# special exception for Lincoln :)
|
|
120
|
+
identity.name.gsub!('Iii', 'III')
|
|
121
|
+
else
|
|
122
|
+
identity.name = author.name.capitalize
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
# if been there, just add contributions according to github
|
|
126
|
+
else
|
|
127
|
+
identity.github.contributions += acct.has_key?('contributions') ? acct['contributions'] : 0
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def get_credentials()
|
|
132
|
+
if @credentials.nil?
|
|
133
|
+
@credentials = false
|
|
134
|
+
if !@auth_file.nil?
|
|
135
|
+
if File.exist? @auth_file
|
|
136
|
+
@credentials = File.read(@auth_file)
|
|
137
|
+
elsif Pathname.new(@auth_file).relative? and File.exist? File.join(ENV['HOME'], @auth_file)
|
|
138
|
+
@credentials = File.read(File.join(ENV['HOME'], @auth_file))
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
class Crawler
|
|
146
|
+
|
|
147
|
+
def initialize(opts = {})
|
|
148
|
+
@auth_file = opts[:auth_file]
|
|
149
|
+
@credentials = nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
PROFILE_URL_TEMPLATE = 'https://api.github.com/users/%s'
|
|
153
|
+
|
|
154
|
+
def enhance(identity)
|
|
155
|
+
identity.extend(IdentityHelper)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def get_credentials()
|
|
159
|
+
if @credentials.nil?
|
|
160
|
+
@credentials = false
|
|
161
|
+
if !@auth_file.nil?
|
|
162
|
+
if File.exist? @auth_file
|
|
163
|
+
@credentials = File.read(@auth_file)
|
|
164
|
+
elsif Pathname.new(@auth_file).relative? and File.exist? File.join(ENV['HOME'], @auth_file)
|
|
165
|
+
@credentials = File.read(File.join(ENV['HOME'], @auth_file))
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def crawl(identity)
|
|
172
|
+
url = identity.github_url
|
|
173
|
+
if url.nil?
|
|
174
|
+
if !identity.github_id.nil?
|
|
175
|
+
url = PROFILE_URL_TEMPLATE % identity.github_id
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# can't find user, give up (no github id or explicit url)
|
|
180
|
+
if url.nil?
|
|
181
|
+
return
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
get_credentials()
|
|
185
|
+
url = url.gsub(/^(https?:\/\/)/, '\1' + @credentials.chomp + '@')
|
|
186
|
+
data = RestClient.get url, :accept => 'application/json'
|
|
187
|
+
identity.github_id = data['login'].downcase
|
|
188
|
+
identity.username = identity.github_id
|
|
189
|
+
identity.github = OpenStruct.new if identity.github.nil?
|
|
190
|
+
identity.github.merge!(OpenStruct.new({
|
|
191
|
+
:id => data['id'],
|
|
192
|
+
:created => data['created_at'],
|
|
193
|
+
:username => identity.username,
|
|
194
|
+
:profile_url => data['html_url'].downcase
|
|
195
|
+
}))
|
|
196
|
+
# only overwrite name if it's longer than the one already there
|
|
197
|
+
if !data['name'].nil? and (identity.name.nil? or data['name'].length > identity.name.length)
|
|
198
|
+
identity.name = data['name'].titleize
|
|
199
|
+
end
|
|
200
|
+
identity.emails ||= []
|
|
201
|
+
identity.emails |= [identity.email].compact
|
|
202
|
+
keys_to_identity = ['email', 'gravatar_id', 'blog', 'location', 'bio', 'company']
|
|
203
|
+
# merge keys, overwriting duplicates
|
|
204
|
+
identity.merge!(OpenStruct.new(data.select { |k, v|
|
|
205
|
+
!v.to_s.strip.empty? and keys_to_identity.include? k
|
|
206
|
+
}))
|
|
207
|
+
if identity.email
|
|
208
|
+
identity.email = identity.email.downcase
|
|
209
|
+
end
|
|
210
|
+
# append email if we got a new one
|
|
211
|
+
identity.emails |= [identity.email]
|
|
212
|
+
# fix blog urls missing http:// prefix
|
|
213
|
+
if !identity.blog.nil? and identity.blog !~ /^https?:\/\//
|
|
214
|
+
identity.blog = 'http://' + identity.blog
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# manually credited commits
|
|
218
|
+
if identity.commits and !identity.contributor
|
|
219
|
+
identity.contributor = OpenStruct.new({
|
|
220
|
+
:commits => identity.commits,
|
|
221
|
+
:emails => [identity.email],
|
|
222
|
+
:name => identity.name
|
|
223
|
+
})
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require 'digest/md5'
|
|
2
|
+
|
|
3
|
+
module Aweplug
|
|
4
|
+
module Extensions
|
|
5
|
+
module Identity
|
|
6
|
+
module Gravatar
|
|
7
|
+
class Crawler
|
|
8
|
+
API_URL_TEMPLATE = 'http://en.gravatar.com/%s.json'
|
|
9
|
+
LANYRD_PROFILE_URL_TEMPLATE = 'http://lanyrd.com/profile/%s'
|
|
10
|
+
|
|
11
|
+
def enhance(identity)
|
|
12
|
+
#identity.extend(IdentityHelper)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def crawl(identity)
|
|
16
|
+
hash = identity.gravatar_id
|
|
17
|
+
if hash.nil?
|
|
18
|
+
hash = Digest::MD5.new().update(identity.email.downcase).hexdigest
|
|
19
|
+
end
|
|
20
|
+
url = API_URL_TEMPLATE % hash
|
|
21
|
+
response = RestClient.get(url, :user_agent => "rest-client") do |rsp, req, res, &blk|
|
|
22
|
+
if rsp.code.eql? 404
|
|
23
|
+
#rsp = RestClient::Response.create('{}', rsp.net_http_res, rsp.args)
|
|
24
|
+
rsp.instance_variable_set(:@code, 200)
|
|
25
|
+
rsp
|
|
26
|
+
else
|
|
27
|
+
rsp.return!(req, res, &blk)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
data = JSON.parse response
|
|
32
|
+
|
|
33
|
+
if data.empty?
|
|
34
|
+
return
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
entry = data['entry'].first
|
|
38
|
+
|
|
39
|
+
keys_to_gravatar = {
|
|
40
|
+
'id' => 'id',
|
|
41
|
+
'hash' => 'hash',
|
|
42
|
+
'profileUrl' => 'profile_url'
|
|
43
|
+
}
|
|
44
|
+
identity.gravatar = OpenStruct.new(entry.select { |k, v|
|
|
45
|
+
!v.to_s.strip.empty? and keys_to_gravatar.has_key? k
|
|
46
|
+
}.inject({}) { |h, (k, v)| h.store(keys_to_gravatar[k], v); h })
|
|
47
|
+
|
|
48
|
+
keys_to_identity = {
|
|
49
|
+
'preferredUsername' => 'preferred_username',
|
|
50
|
+
'displayName' => 'name_cloak',
|
|
51
|
+
'aboutMe' => 'bio',
|
|
52
|
+
'currentLocation' => 'location'
|
|
53
|
+
}
|
|
54
|
+
identity.merge!(OpenStruct.new(entry.select { |k, v|
|
|
55
|
+
!v.to_s.strip.empty? and keys_to_identity.has_key? k
|
|
56
|
+
}.inject({}) { |h, (k, v)| h.store(keys_to_identity[k], v); h }), false)
|
|
57
|
+
|
|
58
|
+
# TODO check if we need a merge here
|
|
59
|
+
if entry.has_key? 'name' and !entry['name'].to_s.strip.empty?
|
|
60
|
+
if identity.names.nil?
|
|
61
|
+
identity.names = OpenStruct.new(entry['name'])
|
|
62
|
+
end
|
|
63
|
+
if identity.name.nil?
|
|
64
|
+
identity.name = identity.names.formatted
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if entry.has_key? 'email' and !entry['email'].to_s.strip.empty?
|
|
69
|
+
email = entry['email'].downcase
|
|
70
|
+
identity.email = email if identity.email.nil?
|
|
71
|
+
identity.emails ||= []
|
|
72
|
+
identity.emails |= [identity.email, email]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
(entry['accounts'] || []).each do |a|
|
|
76
|
+
astruct = OpenStruct.new(a)
|
|
77
|
+
if identity.send(a['shortname']).nil?
|
|
78
|
+
identity.send(a['shortname'] + '=', astruct)
|
|
79
|
+
else
|
|
80
|
+
identity.send(a['shortname']).merge!(astruct)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# grab twitter usernames supplied by _config/identity.yml
|
|
85
|
+
if identity.twitter.nil? and !identity.twitter_username.nil?
|
|
86
|
+
identity.twitter = OpenStruct.new({
|
|
87
|
+
:username => identity.twitter_username,
|
|
88
|
+
:url => 'http://twitter.com/' + identity.twitter_username
|
|
89
|
+
})
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# QUESTION do we need the speaker flag check?
|
|
93
|
+
if identity.speaker and !identity.twitter.nil? and identity.lanyrd.nil?
|
|
94
|
+
identity.lanyrd = OpenStruct.new({
|
|
95
|
+
:username => identity.twitter.username,
|
|
96
|
+
:profile_url => LANYRD_PROFILE_URL_TEMPLATE % identity.twitter.username
|
|
97
|
+
})
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# FIXME either map url to profile_url, or change everywhere else
|
|
101
|
+
(entry['urls'] || []).each do |u|
|
|
102
|
+
identity.urls = [] if identity.urls.nil?
|
|
103
|
+
identity.urls << OpenStruct.new(u)
|
|
104
|
+
if identity.blog.to_s.empty? and u['title'] =~ /blog/i
|
|
105
|
+
identity.blog = u['value']
|
|
106
|
+
end
|
|
107
|
+
if identity.homepage.to_s.empty? and u['title'] =~ /personal/i
|
|
108
|
+
identity.homepage = u['value']
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Aweplug
|
|
2
|
+
module Extensions
|
|
3
|
+
module Identity
|
|
4
|
+
module JBossCommunity
|
|
5
|
+
class Crawler
|
|
6
|
+
PROFILE_URL_TEMPLATE = 'https://community.jboss.org/people/%s'
|
|
7
|
+
|
|
8
|
+
def crawl(identity)
|
|
9
|
+
if !identity.jboss_username.nil?
|
|
10
|
+
identity.jbosscommunity = OpenStruct.new({
|
|
11
|
+
:username => identity.jboss_username,
|
|
12
|
+
:profile_url => PROFILE_URL_TEMPLATE % identity.jboss_username
|
|
13
|
+
})
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if identity.jbosscommunity.nil? and !identity.urls.nil?
|
|
17
|
+
identity.urls.each do |u|
|
|
18
|
+
if u.title =~ /jboss community/i
|
|
19
|
+
identity.jbosscommunity = OpenStruct.new({
|
|
20
|
+
:username => u.value.split('/').last,
|
|
21
|
+
:profile_url => u.value
|
|
22
|
+
})
|
|
23
|
+
identity.jboss_username = identity.jbosscommunity.username
|
|
24
|
+
break
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
# TODO actually rip data from community.jboss.org
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'kramdown'
|
|
3
|
+
require 'aweplug/helpers/git_commit_metadata'
|
|
4
|
+
require 'aweplug/helpers/kramdown_metadata'
|
|
5
|
+
|
|
6
|
+
module Aweplug
|
|
7
|
+
module Extensions
|
|
8
|
+
module Kramdown
|
|
9
|
+
class Quickstart
|
|
10
|
+
include Aweplug::Helper::Git::Commit::Metadata
|
|
11
|
+
|
|
12
|
+
def initialize repository, layout
|
|
13
|
+
@repo = repository
|
|
14
|
+
@layout = layout
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def execute site
|
|
18
|
+
Dir["#{@repo}/**/README.md"].each do |file|
|
|
19
|
+
page = add_to_site site, file
|
|
20
|
+
|
|
21
|
+
metadata = extract_metadata(file)
|
|
22
|
+
metadata[:commits] = commit_info @repo, Pathname.new(file)
|
|
23
|
+
|
|
24
|
+
page.send 'metadata=', @metadata
|
|
25
|
+
# TODO: Upload to DCP
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def extract_metadata(file)
|
|
30
|
+
(Kramdown::Document.new File.readlines(file).join, :input => 'QuickStartParser').root.options[:metadata]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def add_to_site(site, file)
|
|
34
|
+
page = site.engine.load_site_page file
|
|
35
|
+
page.layout = @layout
|
|
36
|
+
page
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'asciidoctor'
|
|
2
|
+
|
|
3
|
+
module Awestruct
|
|
4
|
+
module Extensions
|
|
5
|
+
# Public: Parses (AsciiDoc files currently) and pulls out h2 sections
|
|
6
|
+
# (and their contents), setting them as first class page variables.
|
|
7
|
+
#
|
|
8
|
+
# Examples
|
|
9
|
+
#
|
|
10
|
+
# extension Awestruct::Extensions::Sections.new
|
|
11
|
+
class Sections
|
|
12
|
+
# Internal: Looks for all AsciiDoc files and pulls out the sections,
|
|
13
|
+
# adding them to the page variable.
|
|
14
|
+
#
|
|
15
|
+
# site - The awestruct site variable
|
|
16
|
+
def execute site
|
|
17
|
+
site.pages.each do |page|
|
|
18
|
+
if page.content_syntax =~ /^a(sc)?(ii)?(d(oc)?)?$/
|
|
19
|
+
sections = Asciidoctor.load(page.raw_content).sections
|
|
20
|
+
sections.each do |s|
|
|
21
|
+
r = String.new
|
|
22
|
+
s.blocks.each {|b| r << b.render}
|
|
23
|
+
page.send "#{s.id}=", r
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'open3'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Aweplug
|
|
5
|
+
module Helper
|
|
6
|
+
module Git
|
|
7
|
+
module Commit
|
|
8
|
+
module Metadata
|
|
9
|
+
# Public: Retrieves commit information from the git repo containing the file.
|
|
10
|
+
#
|
|
11
|
+
# repo_root - The directory (relative to the site base) containing the git repo
|
|
12
|
+
# file_path - Path to the file being processed, relative to the site base
|
|
13
|
+
#
|
|
14
|
+
# Returns an array of commit info as json values
|
|
15
|
+
def commit_info(repo_root, file_path)
|
|
16
|
+
o, _ = Open3.capture2(%Q[git --git-dir=#{repo_root}/.git log --date=iso --format='{"author":"%an","date":"%ai"}' -- #{file_path.to_s.sub(/#{repo_root}\//, '')}])
|
|
17
|
+
o.split("\n").map{ |l| JSON.parse l, :symbolize_names => true }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'kramdown'
|
|
2
|
+
require 'kramdown/parser/kramdown'
|
|
3
|
+
|
|
4
|
+
module Kramdown
|
|
5
|
+
module Parser
|
|
6
|
+
class QuickStartParser < Kramdown::Parser::Kramdown
|
|
7
|
+
def initialize source, options
|
|
8
|
+
super
|
|
9
|
+
@block_parsers.unshift :author_metadata
|
|
10
|
+
@block_parsers.unshift :level_metadata
|
|
11
|
+
@block_parsers.unshift :technologies_metadata
|
|
12
|
+
@block_parsers.unshift :target_product_metadata
|
|
13
|
+
@block_parsers.unshift :source_metadata
|
|
14
|
+
@block_parsers.unshift :summary_metadata
|
|
15
|
+
|
|
16
|
+
@root.options[:metadata] = {:author => '', :level => '',
|
|
17
|
+
:technologies => '', :target_product => '',
|
|
18
|
+
:source => '', :summary => ''}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def parse_author_metadata
|
|
22
|
+
@src.pos += @src.matched_size
|
|
23
|
+
@root.options[:metadata][:author] = @src[3]
|
|
24
|
+
end
|
|
25
|
+
define_parser(:author_metadata, /^(Author:)(\s+)(.*?)$/)
|
|
26
|
+
|
|
27
|
+
def parse_level_metadata
|
|
28
|
+
@src.pos += @src.matched_size
|
|
29
|
+
@root.options[:metadata][:level] = @src[3]
|
|
30
|
+
end
|
|
31
|
+
define_parser(:level_metadata, /^(Level:)(\s+)(.*?)$/)
|
|
32
|
+
|
|
33
|
+
def parse_technologies_metadata
|
|
34
|
+
@src.pos += @src.matched_size
|
|
35
|
+
@root.options[:metadata][:technologies] = @src[3]
|
|
36
|
+
end
|
|
37
|
+
define_parser(:technologies_metadata, /^(Technologies:)(\s+)(.*?)$/)
|
|
38
|
+
|
|
39
|
+
def parse_target_product_metadata
|
|
40
|
+
@src.pos += @src.matched_size
|
|
41
|
+
@root.options[:metadata][:target_product] = @src[3]
|
|
42
|
+
end
|
|
43
|
+
define_parser(:target_product_metadata, /^(Target Product:)(\s+)(.*?)$/)
|
|
44
|
+
|
|
45
|
+
def parse_source_metadata
|
|
46
|
+
@src.pos += @src.matched_size
|
|
47
|
+
@root.options[:metadata][:source] = @src[3][1..-2]
|
|
48
|
+
end
|
|
49
|
+
define_parser(:source_metadata, /^(Source:)(\s+)(.*?)$/)
|
|
50
|
+
|
|
51
|
+
def parse_summary_metadata
|
|
52
|
+
@src.pos += @src.matched_size
|
|
53
|
+
@root.options[:metadata][:summary] = @src[3]
|
|
54
|
+
end
|
|
55
|
+
define_parser(:summary_metadata, /^(Summary:)(\s+)(.*?)$/)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
File without changes
|
data/lib/aweplug.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Identity Collector' do
|
|
4
|
+
|
|
5
|
+
it 'may have one or more crawlers' do
|
|
6
|
+
pending "Not implemented"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'must have one storage' do
|
|
10
|
+
pending "Not implemented"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'may be configurable via a block' do
|
|
14
|
+
pending "Not implemented"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'may be configured via method calls' do
|
|
18
|
+
pending "Not implemented"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'must respond to execute(site)' do
|
|
22
|
+
pending "Not implemented"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Storage' do
|
|
4
|
+
|
|
5
|
+
it 'must respond to write' do
|
|
6
|
+
pending "Not implemented"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'must respond to read' do
|
|
10
|
+
pending "Not implemented"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'must respond to fetch' do
|
|
14
|
+
pending "Not implemented"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'must respond to exist' do
|
|
18
|
+
pending "Not implemented"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'must respond to delete' do
|
|
22
|
+
pending "Not implemented"
|
|
23
|
+
end
|
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
|
|
3
|
+
Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
|
|
4
|
+
|
|
5
|
+
RSpec.configure do |config|
|
|
6
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
7
|
+
config.run_all_when_everything_filtered = true
|
|
8
|
+
config.filter_run :focus
|
|
9
|
+
|
|
10
|
+
config.order = 'random'
|
|
11
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
shared_examples_for 'a crawler' do
|
|
2
|
+
it 'may require authentication' do
|
|
3
|
+
if crawler.respond_to? :authenticate_using, false
|
|
4
|
+
expect { crawler.crawl }.to raise_error
|
|
5
|
+
else
|
|
6
|
+
expect { crawler.crawl }.to_not raise_error
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'must respond to crawl' do
|
|
11
|
+
should respond_to(:crawl)
|
|
12
|
+
end
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: aweplug
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0.a2
|
|
5
|
+
prerelease: 6
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- LightGuard
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-12-09 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: octokit
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.24.0
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 1.24.0
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: faraday
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: 0.8.7
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: 0.8.7
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: faraday_middleware
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.9.0
|
|
54
|
+
type: :runtime
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 0.9.0
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: guard-rspec
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ~>
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: 3.0.0
|
|
70
|
+
type: :development
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ~>
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: 3.0.0
|
|
78
|
+
- !ruby/object:Gem::Dependency
|
|
79
|
+
name: rake
|
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
|
81
|
+
none: false
|
|
82
|
+
requirements:
|
|
83
|
+
- - ~>
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: 10.0.4
|
|
86
|
+
type: :development
|
|
87
|
+
prerelease: false
|
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
89
|
+
none: false
|
|
90
|
+
requirements:
|
|
91
|
+
- - ~>
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 10.0.4
|
|
94
|
+
description: A set of Awestruct extensions for building a project website
|
|
95
|
+
email:
|
|
96
|
+
- lightguard.jp@gmail.com
|
|
97
|
+
executables: []
|
|
98
|
+
extensions: []
|
|
99
|
+
extra_rdoc_files: []
|
|
100
|
+
files:
|
|
101
|
+
- .gitignore
|
|
102
|
+
- .rspec
|
|
103
|
+
- Gemfile
|
|
104
|
+
- Guardfile
|
|
105
|
+
- LICENSE.txt
|
|
106
|
+
- README.adoc
|
|
107
|
+
- README.md
|
|
108
|
+
- Rakefile
|
|
109
|
+
- aweplug.gemspec
|
|
110
|
+
- lib/aweplug.rb
|
|
111
|
+
- lib/aweplug/extensions/identities.rb
|
|
112
|
+
- lib/aweplug/extensions/identity/confluence.rb
|
|
113
|
+
- lib/aweplug/extensions/identity/github.rb
|
|
114
|
+
- lib/aweplug/extensions/identity/gravatar.rb
|
|
115
|
+
- lib/aweplug/extensions/identity/jbosscommunity.rb
|
|
116
|
+
- lib/aweplug/extensions/kramdown_quickstart.rb
|
|
117
|
+
- lib/aweplug/extensions/sections.rb
|
|
118
|
+
- lib/aweplug/helpers/.gitkeep
|
|
119
|
+
- lib/aweplug/helpers/git_commit_metadata.rb
|
|
120
|
+
- lib/aweplug/helpers/kramdown_metadata.rb
|
|
121
|
+
- lib/aweplug/transformers/.gitkeep
|
|
122
|
+
- lib/aweplug/version.rb
|
|
123
|
+
- spec/aweplug/extensions/identity/collector_spec.rb
|
|
124
|
+
- spec/aweplug/extensions/identity/github_spec.rb
|
|
125
|
+
- spec/aweplug/extensions/identity/storage_spec.rb
|
|
126
|
+
- spec/spec_helper.rb
|
|
127
|
+
- spec/support/aweplug/extensions/identity/crawler_examples.rb
|
|
128
|
+
homepage: https://github.com/awestruct/aweplug
|
|
129
|
+
licenses: []
|
|
130
|
+
post_install_message:
|
|
131
|
+
rdoc_options: []
|
|
132
|
+
require_paths:
|
|
133
|
+
- lib
|
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
|
+
none: false
|
|
136
|
+
requirements:
|
|
137
|
+
- - ! '>='
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: '0'
|
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
|
+
none: false
|
|
142
|
+
requirements:
|
|
143
|
+
- - ! '>'
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: 1.3.1
|
|
146
|
+
requirements: []
|
|
147
|
+
rubyforge_project:
|
|
148
|
+
rubygems_version: 1.8.25
|
|
149
|
+
signing_key:
|
|
150
|
+
specification_version: 3
|
|
151
|
+
summary: This set of Awestruct extensions includes helpful tools, extensions and
|
|
152
|
+
helpers for building a website using Awestruct. It includes extensions for accessing
|
|
153
|
+
Github, JIRA, managing identities and others.
|
|
154
|
+
test_files:
|
|
155
|
+
- spec/aweplug/extensions/identity/collector_spec.rb
|
|
156
|
+
- spec/aweplug/extensions/identity/github_spec.rb
|
|
157
|
+
- spec/aweplug/extensions/identity/storage_spec.rb
|
|
158
|
+
- spec/spec_helper.rb
|
|
159
|
+
- spec/support/aweplug/extensions/identity/crawler_examples.rb
|
|
160
|
+
has_rdoc:
|