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 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
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --fail-fast
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
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
@@ -0,0 +1,3 @@
1
+ == aweplug
2
+
3
+ A set of Awestruct extensions aimed at creating OSS project websites.
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
@@ -0,0 +1,4 @@
1
+ module Aweplug
2
+ VERSION='1.0.0.a2'
3
+ end
4
+
data/lib/aweplug.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "aweplug/version"
2
+
3
+ module Aweplug
4
+ # Your code goes here...
5
+ end
@@ -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,7 @@
1
+ require 'spec_helper'
2
+ require 'aweplug/extensions/identity/github'
3
+
4
+ describe 'Github Crawler' do
5
+ let(:crawler) { Aweplug::Extensions::Identity::GitHub::Crawler.new }
6
+ it_should_behave_like 'a crawler'
7
+ 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
@@ -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: