cutting_edge 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +7 -2
- data/Gemfile.lock +130 -0
- data/LICENSE +68 -81
- data/Procfile +1 -0
- data/README.md +272 -74
- data/Rakefile +0 -5
- data/bin/cutting_edge +60 -45
- data/config.rb +55 -0
- data/cutting_edge.gemspec +33 -4
- data/heroku.config.rb +20 -0
- data/lib/cutting_edge.rb +1 -1
- data/lib/cutting_edge/app.rb +95 -19
- data/lib/cutting_edge/langs.rb +7 -1
- data/lib/cutting_edge/langs/python.rb +5 -1
- data/lib/cutting_edge/langs/ruby.rb +5 -1
- data/lib/cutting_edge/langs/rust.rb +5 -1
- data/lib/cutting_edge/public/images/error.svg +24 -0
- data/lib/cutting_edge/public/images/languages/python.svg +1 -0
- data/lib/cutting_edge/public/images/languages/ruby.svg +1 -0
- data/lib/cutting_edge/public/images/languages/rust.svg +1 -0
- data/lib/cutting_edge/public/images/ok.svg +24 -0
- data/lib/cutting_edge/public/javascript/clipboard.min.js +7 -0
- data/lib/cutting_edge/public/javascript/cuttingedge.js +53 -0
- data/lib/cutting_edge/public/stylesheets/primer.css +22 -0
- data/lib/cutting_edge/repo.rb +124 -18
- data/lib/cutting_edge/templates/_footer.html.erb +3 -0
- data/lib/cutting_edge/templates/_header.html.erb +8 -0
- data/lib/cutting_edge/templates/_overview.html.erb +9 -0
- data/lib/cutting_edge/templates/badge.svg.erb +39 -0
- data/lib/cutting_edge/templates/index.html.erb +62 -0
- data/lib/cutting_edge/templates/info.html.erb +101 -0
- data/lib/cutting_edge/templates/mail.html.erb +163 -0
- data/lib/cutting_edge/workers/badge.rb +33 -11
- data/lib/cutting_edge/workers/dependency.rb +36 -16
- data/lib/cutting_edge/workers/helpers.rb +8 -0
- data/lib/cutting_edge/workers/mail.rb +38 -0
- data/projects.yml +25 -0
- data/spec/app_spec.rb +115 -0
- data/spec/badge_worker_spec.rb +77 -0
- data/spec/dependency_worker_spec.rb +132 -0
- data/spec/email_worker_spec.rb +43 -0
- data/spec/fixtures.rb +180 -0
- data/spec/fixtures/projects.yml +27 -0
- data/spec/langs/python_spec.rb +47 -5
- data/spec/langs/ruby_spec.rb +105 -0
- data/spec/langs/rust_spec.rb +31 -0
- data/spec/repo_spec.rb +52 -0
- data/spec/spec_helper.rb +9 -1
- metadata +43 -15
- data/lib/cutting_edge/badge.rb +0 -46
data/Rakefile
CHANGED
data/bin/cutting_edge
CHANGED
@@ -1,72 +1,87 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.expand_path('../../lib/cutting_edge/app.rb', __FILE__)
|
4
3
|
require 'yaml'
|
5
4
|
require 'rufus-scheduler'
|
5
|
+
require 'optparse'
|
6
|
+
require 'semantic_logger'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
gollum:
|
11
|
-
api_token: secret
|
12
|
-
gollum-lib:
|
13
|
-
api_token: secret
|
14
|
-
locations: [gemspec.rb]
|
15
|
-
dependency_types: [runtime, development]
|
16
|
-
singingwolfboy:
|
17
|
-
flask-dance:
|
18
|
-
language: python
|
19
|
-
rust-lang:
|
20
|
-
crates.io:
|
21
|
-
language: rust
|
22
|
-
api_token: secret
|
23
|
-
gitlab:
|
24
|
-
cthowl01:
|
25
|
-
team-chess-ruby:
|
26
|
-
api_token: secret
|
27
|
-
YAML
|
8
|
+
module CuttingEdge
|
9
|
+
REFRESH_SCHEDULE = '1h'
|
10
|
+
end
|
28
11
|
|
29
12
|
options = {
|
30
13
|
:port => 4567,
|
31
|
-
:bind => '0.0.0.0'
|
14
|
+
:bind => '0.0.0.0'
|
32
15
|
}
|
33
16
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
17
|
+
opts = OptionParser.new do |opts|
|
18
|
+
opts.banner = 'CuttingEdge is a dependency monitoring application.
|
19
|
+
|
20
|
+
Usage:
|
21
|
+
cutting_edge [options] [projects]
|
22
|
+
|
23
|
+
Arguments:
|
24
|
+
[projects] Path to the YAML file which defines the projects to be monitored. If not specified, projects.yml in the current working directory is used.
|
25
|
+
'
|
26
|
+
opts.separator ''
|
27
|
+
|
28
|
+
opts.on('-h', '--host [HOST]', 'Specify the hostname or IP address to listen on. Default: \'0.0.0.0\'.') do |host|
|
29
|
+
options[:bind] = host
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on('-p', '--port [PORT]', 'Specify the port to bind to. Default: \'4567\'.') do |port|
|
33
|
+
begin
|
34
|
+
# don't use 'port.to_i' here... it doesn't raise errors which might result in a nice confusion later on
|
35
|
+
options[:port] = Integer(port)
|
36
|
+
rescue ArgumentError
|
37
|
+
puts "Error: '#{port}' is not a valid port number."
|
38
|
+
exit 1
|
44
39
|
end
|
45
40
|
end
|
41
|
+
|
42
|
+
opts.on('-c', '--config [FILE]', 'Specify path to a .rb configuration file. Default: config.rb') do |file|
|
43
|
+
options[:config] = file || 'config.rb'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
opts.parse!
|
49
|
+
rescue OptionParser::InvalidOption => e
|
50
|
+
puts "cutting_edge: #{e.message}"
|
51
|
+
puts 'cutting_edge: try \'cutting_edge --help\' for more information'
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
|
55
|
+
if cfg = options[:config]
|
56
|
+
# If the path begins with a '/' it will be considered an absolute path,
|
57
|
+
# otherwise it will be relative to the CWD
|
58
|
+
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
|
59
|
+
require cfg
|
46
60
|
end
|
47
61
|
|
62
|
+
# Only require the app after loading the optional config file, to give user the chance to define constants.
|
63
|
+
require File.expand_path('../../lib/cutting_edge/app.rb', __FILE__)
|
64
|
+
|
65
|
+
include CuttingEdgeHelpers
|
66
|
+
repositories = load_repositories(ARGV[0] || 'projects.yml')
|
67
|
+
repositories.merge!(CuttingEdge::REPOSITORIES) if defined?(CuttingEdge::REPOSITORIES)
|
68
|
+
|
69
|
+
CuttingEdge::STORE = Moneta.new(:Memory) unless defined?(CuttingEdge::STORE)
|
70
|
+
CuttingEdge::App.set(:store, CuttingEdge::STORE)
|
71
|
+
|
48
72
|
# Need to initialize the log like this once, because otherwise it only becomes available after the Sinatra app has received a request...
|
49
73
|
::SemanticLogger.add_appender(file_name: "#{CuttingEdge::App.environment}.log")
|
50
74
|
|
51
75
|
CuttingEdge::App.set(:repositories, repositories)
|
52
|
-
CuttingEdge::App.set(:store, store)
|
53
76
|
CuttingEdge::App.set(:enable_logging, true)
|
54
77
|
|
55
|
-
puts
|
78
|
+
puts 'Scheduling Jobs...'
|
56
79
|
scheduler = Rufus::Scheduler.new
|
57
|
-
scheduler.every(
|
80
|
+
scheduler.every(CuttingEdge::REFRESH_SCHEDULE) do
|
58
81
|
worker_fetch_all(repositories.values)
|
59
82
|
end
|
60
|
-
scheduler.every('1h5m') do
|
61
|
-
worker_all_badges(repositories.values)
|
62
|
-
end
|
63
83
|
|
64
|
-
puts
|
65
|
-
include CuttingEdgeHelpers
|
84
|
+
puts 'Running Workers a first time...'
|
66
85
|
worker_fetch_all(repositories.values)
|
67
86
|
|
68
|
-
sleep 5
|
69
|
-
worker_all_badges(repositories.values)
|
70
|
-
|
71
|
-
puts "Starting Sinatra..."
|
72
87
|
CuttingEdge::App.run!(options)
|
data/config.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Example config.rb for CuttingEdge
|
2
|
+
# All the settings below are purely optional: they all have sane defaults.
|
3
|
+
|
4
|
+
# Configure mail server settings (outside the CuttingEdge module)
|
5
|
+
require 'mail'
|
6
|
+
Mail.defaults do
|
7
|
+
delivery_method :smtp, address: 'localhost', port: 25
|
8
|
+
end
|
9
|
+
|
10
|
+
module CuttingEdge
|
11
|
+
REFRESH_SCHEDULE = '1h' # How often to run workers to check for changes to dependency status. Examples of valid values: '10d', '10m', etc.
|
12
|
+
SERVER_HOST = 'mydependencymonitoring.com' # At what domain is this CuttingEdge instance running? Defaults to 'localhost'
|
13
|
+
SERVER_URL = "https://#{SERVER_HOST}:4567" # The URL used to refer to this CuttingEdge instance, for instance in e-mails. Defaults to 'http://#{SERVER_HOST}'
|
14
|
+
|
15
|
+
MAIL_TO = 'mydeps@mymail.com' # Default address to send email to. If set to false (=default!), don't send any e-mails except for repositories that have their 'email:' attribute set in projects.yml
|
16
|
+
MAIL_FROM = "cutting_edge@#{SERVER_HOST}" # From Address used for sending e-mails. Default: "cutting_edge@#{SERVER_HOST}"
|
17
|
+
MAIL_TEMPLATE = <<EOF
|
18
|
+
Define your own ERB template for e-mail updates from CuttingEdge here!
|
19
|
+
Of course, you can also File.read it from a separate template file.
|
20
|
+
See lib/cutting_edge/templates/mail.html.erb for the default template, and the available variables.
|
21
|
+
EOF
|
22
|
+
|
23
|
+
SECRET_TOKEN = 'mysecrettoken' # Global administrative secret
|
24
|
+
|
25
|
+
LAST_VERSION_TIMEOUT = 5 # Number of seconds after which to fail when trying to determine the latest version for a dependency.
|
26
|
+
|
27
|
+
BADGE_COLORS = {
|
28
|
+
ok: 'blue',
|
29
|
+
outdated_patch: '#dfb317',
|
30
|
+
outdated_minor: '#fe7d37',
|
31
|
+
outdated_major: '#e05d44',
|
32
|
+
unknown: '#9f9f9f'
|
33
|
+
} # Redefine the colors used in SVG badges
|
34
|
+
|
35
|
+
# The following will allow you to define projects on your own GitLab or Gitea server in projects.yml
|
36
|
+
# This will allow you to use the 'mygitlab' and 'mygitea' keys, respectively, in projects.yml
|
37
|
+
require './lib/cutting_edge/repo.rb'
|
38
|
+
define_gitlab_server('mygitlab', 'https://mygitlab.com')
|
39
|
+
define_gitea_server('mygitea', 'https://mygitea.com')
|
40
|
+
# Now you may use your own server instance in projects.yml like so:
|
41
|
+
# mygitlab:
|
42
|
+
# orgname:
|
43
|
+
# projectname:
|
44
|
+
# language: rust
|
45
|
+
# ruby_project:
|
46
|
+
# language ruby
|
47
|
+
|
48
|
+
# You may also define additional repositories programatically as follows.
|
49
|
+
# These will be added to the repositories defined in projects.yml.
|
50
|
+
# This may be useful, for instance, if you want to use environment variables to keep information secret.
|
51
|
+
# Note: you need to require './lib/cutting_edge/repo.rb' first
|
52
|
+
REPOSITORIES = {
|
53
|
+
"gitlab/#{ENV['PRIVATE_REPO1_ORG']}/#{ENV['PRIVATE_REPO1_NAME']}" => GitlabRepository.new(org: ENV['PRIVATE_REPO1_ORG'], name: ENV['PRIVATE_REPO1_NAME'], lang: 'python', auth_token: ENV['PRIVATE_REPO1_TOKEN'], hide: true)
|
54
|
+
}
|
55
|
+
end
|
data/cutting_edge.gemspec
CHANGED
@@ -5,8 +5,8 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.required_ruby_version = '>= 2.4'
|
6
6
|
|
7
7
|
s.name = 'cutting_edge'
|
8
|
-
s.version = '0.
|
9
|
-
s.date = '2020-02
|
8
|
+
s.version = '0.1'
|
9
|
+
s.date = '2020-11-02'
|
10
10
|
s.license = 'GPL-3.0-only'
|
11
11
|
|
12
12
|
s.summary = 'Self-hosted dependency monitoring, including shiny badges.'
|
@@ -25,32 +25,61 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency 'sucker_punch', '~> 2.1'
|
26
26
|
s.add_dependency 'sinatra', '~> 2.0'
|
27
27
|
s.add_dependency 'moneta', '~> 1.2'
|
28
|
-
s.add_dependency 'victor', '~> 0.2.8'
|
29
28
|
s.add_dependency 'rufus-scheduler', '~> 3.6'
|
30
29
|
s.add_dependency 'sinatra-logger', '~> 0.3'
|
31
30
|
s.add_dependency 'toml-rb', '~> 2.0'
|
31
|
+
s.add_dependency 'mail', '~> 2.7'
|
32
|
+
|
32
33
|
# = MANIFEST =
|
33
34
|
s.files = %w[
|
34
35
|
Gemfile
|
36
|
+
Gemfile.lock
|
35
37
|
LICENSE
|
38
|
+
Procfile
|
36
39
|
README.md
|
37
40
|
Rakefile
|
38
41
|
bin/cutting_edge
|
42
|
+
config.rb
|
39
43
|
cutting_edge.gemspec
|
44
|
+
heroku.config.rb
|
40
45
|
lib/cutting_edge.rb
|
41
46
|
lib/cutting_edge/app.rb
|
42
|
-
lib/cutting_edge/badge.rb
|
43
47
|
lib/cutting_edge/langs.rb
|
44
48
|
lib/cutting_edge/langs/python.rb
|
45
49
|
lib/cutting_edge/langs/ruby.rb
|
46
50
|
lib/cutting_edge/langs/rust.rb
|
51
|
+
lib/cutting_edge/public/images/error.svg
|
52
|
+
lib/cutting_edge/public/images/languages/python.svg
|
53
|
+
lib/cutting_edge/public/images/languages/ruby.svg
|
54
|
+
lib/cutting_edge/public/images/languages/rust.svg
|
55
|
+
lib/cutting_edge/public/images/ok.svg
|
56
|
+
lib/cutting_edge/public/javascript/clipboard.min.js
|
57
|
+
lib/cutting_edge/public/javascript/cuttingedge.js
|
58
|
+
lib/cutting_edge/public/stylesheets/primer.css
|
47
59
|
lib/cutting_edge/repo.rb
|
60
|
+
lib/cutting_edge/templates/_footer.html.erb
|
61
|
+
lib/cutting_edge/templates/_header.html.erb
|
62
|
+
lib/cutting_edge/templates/_overview.html.erb
|
63
|
+
lib/cutting_edge/templates/badge.svg.erb
|
64
|
+
lib/cutting_edge/templates/index.html.erb
|
65
|
+
lib/cutting_edge/templates/info.html.erb
|
66
|
+
lib/cutting_edge/templates/mail.html.erb
|
48
67
|
lib/cutting_edge/versions.rb
|
49
68
|
lib/cutting_edge/workers/badge.rb
|
50
69
|
lib/cutting_edge/workers/dependency.rb
|
51
70
|
lib/cutting_edge/workers/helpers.rb
|
71
|
+
lib/cutting_edge/workers/mail.rb
|
72
|
+
projects.yml
|
73
|
+
spec/app_spec.rb
|
74
|
+
spec/badge_worker_spec.rb
|
75
|
+
spec/dependency_worker_spec.rb
|
76
|
+
spec/email_worker_spec.rb
|
77
|
+
spec/fixtures.rb
|
78
|
+
spec/fixtures/projects.yml
|
52
79
|
spec/langs/python_spec.rb
|
80
|
+
spec/langs/ruby_spec.rb
|
53
81
|
spec/langs/rust_spec.rb
|
82
|
+
spec/repo_spec.rb
|
54
83
|
spec/spec_helper.rb
|
55
84
|
]
|
56
85
|
# = MANIFEST =
|
data/heroku.config.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Default settings required for Heroku deployment
|
2
|
+
|
3
|
+
module CuttingEdge
|
4
|
+
SERVER_HOST = "#{ENV['HEROKU_APP_NAME']}.herokuapp.com" # At what domain is this CuttingEdge instance running?
|
5
|
+
SERVER_URL = "https://#{SERVER_HOST}"
|
6
|
+
MAIL_TO = ENV['CUTTING_EDGE_MAIL_TO'] if ENV['CUTTING_EDGE_MAIL_TO']
|
7
|
+
|
8
|
+
# Your additional configuration goes here.
|
9
|
+
# If you are going to host the repository containing this file publically (e.g. on GitHub), please read:
|
10
|
+
# https://github.com/repotag/cutting_edge/blob/master/README.md#Defining-repositories-in-configrb
|
11
|
+
end
|
12
|
+
|
13
|
+
# Needed to write to Heroku logs.
|
14
|
+
::SemanticLogger.add_appender(io: $stderr)
|
15
|
+
|
16
|
+
# Configure mail server settings
|
17
|
+
require 'mail'
|
18
|
+
Mail.defaults do
|
19
|
+
delivery_method :smtp, address: ENV['MAILGUN_SMTP_SERVER'], port: ENV['MAILGUN_SMTP_PORT'], user_name: ENV['MAILGUN_SMTP_LOGIN'], password: ENV['MAILGUN_SMTP_PASSWORD'], domain: CuttingEdge::SERVER_HOST
|
20
|
+
end
|
data/lib/cutting_edge.rb
CHANGED
data/lib/cutting_edge/app.rb
CHANGED
@@ -9,18 +9,10 @@ require File.expand_path('../../cutting_edge.rb', __FILE__)
|
|
9
9
|
require File.expand_path('../repo.rb', __FILE__)
|
10
10
|
require File.expand_path('../workers/dependency.rb', __FILE__)
|
11
11
|
require File.expand_path('../workers/badge.rb', __FILE__)
|
12
|
+
require File.expand_path('../workers/mail.rb', __FILE__)
|
12
13
|
|
13
14
|
module CuttingEdgeHelpers
|
14
|
-
|
15
|
-
repositories.each do |repo|
|
16
|
-
worker_generate_badge(repo)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def worker_generate_badge(repo)
|
21
|
-
BadgeWorker.perform_async(repo.identifier)
|
22
|
-
end
|
23
|
-
|
15
|
+
|
24
16
|
def worker_fetch_all(repositories)
|
25
17
|
repositories.each do |repo|
|
26
18
|
worker_fetch(repo)
|
@@ -28,38 +20,110 @@ module CuttingEdgeHelpers
|
|
28
20
|
end
|
29
21
|
|
30
22
|
def worker_fetch(repo)
|
31
|
-
DependencyWorker.perform_async(repo.identifier, repo.lang, repo.locations, repo.dependency_types)
|
23
|
+
DependencyWorker.perform_async(repo.identifier, repo.lang, repo.locations, repo.dependency_types, repo.contact_email, repo.auth_token)
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_repositories(path)
|
27
|
+
repositories = {}
|
28
|
+
begin
|
29
|
+
YAML.load(File.read(path)).each do |source, orgs|
|
30
|
+
orgs.each do |org, value|
|
31
|
+
value.each do |name, settings|
|
32
|
+
cfg = settings.is_a?(Hash) ? settings : {}
|
33
|
+
repo = Object.const_get("CuttingEdge::#{source.capitalize}Repository").new(org: org, name: name, lang: cfg.fetch('language', nil), locations: cfg.fetch('locations', nil), branch: cfg.fetch('branch', nil), email: cfg.fetch('email', CuttingEdge::MAIL_TO), auth_token: cfg.fetch('auth_token', nil), hide: cfg.fetch('hide', false))
|
34
|
+
repo.dependency_types = cfg['dependency_types'].map {|dep| dep.to_sym} if cfg['dependency_types'].is_a?(Array)
|
35
|
+
repositories["#{source}/#{org}/#{name}"] = repo
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue SyntaxError, Errno::ENOENT => e
|
40
|
+
puts "Error: #{path} does not contain a valid YAML project definition."
|
41
|
+
if ENV['RACK_ENV'] == 'test'
|
42
|
+
return nil
|
43
|
+
else
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
repositories
|
32
48
|
end
|
33
49
|
end
|
34
50
|
|
35
|
-
|
36
51
|
module CuttingEdge
|
37
|
-
LAST_VERSION_TIMEOUT = 5
|
38
52
|
|
53
|
+
LAST_VERSION_TIMEOUT = 5
|
54
|
+
SERVER_HOST = 'localhost' unless defined?(SERVER_HOST)
|
55
|
+
SERVER_URL = "http://#{SERVER_HOST}" unless defined?(SERVER_URL)
|
56
|
+
MAIL_TO = false unless defined?(MAIL_TO) # Default address to send email to. If set to false, don't send any e-mails except for repositories that have their 'email' attribute set.
|
57
|
+
MAIL_FROM = "cutting_edge@#{SERVER_HOST}" unless defined?(MAIL_FROM)
|
58
|
+
|
39
59
|
class App < Sinatra::Base
|
40
60
|
include CuttingEdgeHelpers
|
41
61
|
|
62
|
+
set :views, ::File.join(::File.dirname(__FILE__), 'templates')
|
63
|
+
Tilt.register Tilt::ERBTemplate, 'html.erb'
|
64
|
+
set :public_folder, ::File.join(::File.dirname(__FILE__), 'public')
|
42
65
|
logger filename: "#{settings.environment}.log", level: :trace
|
43
66
|
|
44
67
|
before do
|
45
68
|
@store = settings.store
|
46
69
|
end
|
47
70
|
|
48
|
-
get
|
71
|
+
get '/' do
|
72
|
+
hidden_repos, public_repos = CuttingEdge::App.repositories.partition{|_, repo| repo.hidden?}.map(&:to_h)
|
73
|
+
@hidden_repos_exist = !hidden_repos.empty?
|
74
|
+
@repos = public_repos
|
75
|
+
erb :index
|
76
|
+
end
|
77
|
+
|
78
|
+
post '/hidden_repos' do
|
79
|
+
payload = JSON.parse(request.body.read)
|
80
|
+
if valid_token?(payload['token'])
|
81
|
+
@repos = CuttingEdge::App.repositories.select{|_, repo| repo.hidden?}
|
82
|
+
partial = Tilt::ERBTemplate.new(::File.join(CuttingEdge::App.views, '_overview.html.erb'))
|
83
|
+
{partial: partial.render(self)}.to_json
|
84
|
+
else
|
85
|
+
status 401
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
get %r{/(.+)/(.+)/(.+)/info/json} do |source, org, name|
|
49
91
|
repo_defined?(source, org, name)
|
92
|
+
validate_repo_token(params[:token]) if @repo.hidden?
|
50
93
|
content_type :json
|
51
|
-
@store[@repo.identifier]
|
94
|
+
data = @store[@repo.identifier]
|
95
|
+
if data
|
96
|
+
data.merge({:language => @repo.lang}).to_json
|
97
|
+
else
|
98
|
+
status 500
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
get %r{/(.+)/(.+)/(.+)/info} do |source, org, name|
|
103
|
+
repo_defined?(source, org, name)
|
104
|
+
validate_repo_token(params[:token]) if @repo.hidden?
|
105
|
+
@name = name
|
106
|
+
@svg = url("/#{source}/#{org}/#{name}/svg")
|
107
|
+
@svg = "#{@svg}?token=#{@repo.hidden_token}" if @repo.hidden?
|
108
|
+
@md = "[![Cutting Edge Dependency Status](#{@svg} 'Cutting Edge Dependency Status')](#{url("/#{source}/#{org}/#{name}/info")})"
|
109
|
+
@colors = {ok: 'green', outdated_patch: 'yellow', outdated_minor: 'orange', outdated_major: 'red', unknown: 'gray'}
|
110
|
+
@specs = @store[@repo.identifier]
|
111
|
+
@project_url = @repo.url_for_project
|
112
|
+
@language = @repo.lang
|
113
|
+
erb :info
|
52
114
|
end
|
53
115
|
|
54
116
|
get %r{/(.+)/(.+)/(.+)/svg} do |source, org, name|
|
55
117
|
repo_defined?(source, org, name)
|
118
|
+
validate_repo_token(params[:token]) if @repo.hidden?
|
119
|
+
cache_control no_cache: true
|
56
120
|
content_type 'image/svg+xml'
|
57
121
|
@store["svg-#{@repo.identifier}"]
|
58
122
|
end
|
59
123
|
|
60
124
|
post %r{/(.+)/(.+)/(.+)/refresh} do |source, org, name|
|
61
125
|
repo_defined?(source, org, name)
|
62
|
-
if
|
126
|
+
if valid_token?(params[:token])
|
63
127
|
worker_fetch(@repo)
|
64
128
|
status 200
|
65
129
|
else
|
@@ -68,10 +132,22 @@ module CuttingEdge
|
|
68
132
|
end
|
69
133
|
|
70
134
|
private
|
71
|
-
|
135
|
+
|
136
|
+
def not_found
|
137
|
+
halt 404, '404 Not Found'
|
138
|
+
end
|
139
|
+
|
140
|
+
def valid_token?(token)
|
141
|
+
defined?(::CuttingEdge::SECRET_TOKEN) && token == ::CuttingEdge::SECRET_TOKEN
|
142
|
+
end
|
143
|
+
|
144
|
+
def validate_repo_token(token)
|
145
|
+
not_found unless token == @repo.hidden_token
|
146
|
+
end
|
147
|
+
|
72
148
|
def repo_defined?(source, org, name)
|
73
|
-
|
149
|
+
not_found unless @repo = settings.repositories["#{source}/#{org}/#{name}"]
|
74
150
|
end
|
75
|
-
|
151
|
+
|
76
152
|
end
|
77
153
|
end
|