cutting_edge 0.0.1 → 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -2
  3. data/Gemfile.lock +130 -0
  4. data/LICENSE +68 -81
  5. data/Procfile +1 -0
  6. data/README.md +272 -74
  7. data/Rakefile +0 -5
  8. data/bin/cutting_edge +60 -45
  9. data/config.rb +55 -0
  10. data/cutting_edge.gemspec +33 -4
  11. data/heroku.config.rb +20 -0
  12. data/lib/cutting_edge.rb +1 -1
  13. data/lib/cutting_edge/app.rb +95 -19
  14. data/lib/cutting_edge/langs.rb +7 -1
  15. data/lib/cutting_edge/langs/python.rb +5 -1
  16. data/lib/cutting_edge/langs/ruby.rb +5 -1
  17. data/lib/cutting_edge/langs/rust.rb +5 -1
  18. data/lib/cutting_edge/public/images/error.svg +24 -0
  19. data/lib/cutting_edge/public/images/languages/python.svg +1 -0
  20. data/lib/cutting_edge/public/images/languages/ruby.svg +1 -0
  21. data/lib/cutting_edge/public/images/languages/rust.svg +1 -0
  22. data/lib/cutting_edge/public/images/ok.svg +24 -0
  23. data/lib/cutting_edge/public/javascript/clipboard.min.js +7 -0
  24. data/lib/cutting_edge/public/javascript/cuttingedge.js +53 -0
  25. data/lib/cutting_edge/public/stylesheets/primer.css +22 -0
  26. data/lib/cutting_edge/repo.rb +124 -18
  27. data/lib/cutting_edge/templates/_footer.html.erb +3 -0
  28. data/lib/cutting_edge/templates/_header.html.erb +8 -0
  29. data/lib/cutting_edge/templates/_overview.html.erb +9 -0
  30. data/lib/cutting_edge/templates/badge.svg.erb +39 -0
  31. data/lib/cutting_edge/templates/index.html.erb +62 -0
  32. data/lib/cutting_edge/templates/info.html.erb +101 -0
  33. data/lib/cutting_edge/templates/mail.html.erb +163 -0
  34. data/lib/cutting_edge/workers/badge.rb +33 -11
  35. data/lib/cutting_edge/workers/dependency.rb +36 -16
  36. data/lib/cutting_edge/workers/helpers.rb +8 -0
  37. data/lib/cutting_edge/workers/mail.rb +38 -0
  38. data/projects.yml +25 -0
  39. data/spec/app_spec.rb +115 -0
  40. data/spec/badge_worker_spec.rb +77 -0
  41. data/spec/dependency_worker_spec.rb +132 -0
  42. data/spec/email_worker_spec.rb +43 -0
  43. data/spec/fixtures.rb +180 -0
  44. data/spec/fixtures/projects.yml +27 -0
  45. data/spec/langs/python_spec.rb +47 -5
  46. data/spec/langs/ruby_spec.rb +105 -0
  47. data/spec/langs/rust_spec.rb +31 -0
  48. data/spec/repo_spec.rb +52 -0
  49. data/spec/spec_helper.rb +9 -1
  50. metadata +43 -15
  51. data/lib/cutting_edge/badge.rb +0 -46
data/Rakefile CHANGED
@@ -55,11 +55,6 @@ def gemspec_file
55
55
  "#{name}.gemspec"
56
56
  end
57
57
 
58
- desc "Build the gem file."
59
- task :build do
60
- system "gem build gollum_git_adapter_specs.gemspec"
61
- end
62
-
63
58
  def gem_file
64
59
  "#{name}-#{version}.gem"
65
60
  end
@@ -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
- config = <<YAML
8
- github:
9
- gollum:
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
- store = Moneta.new(:Memory)
35
-
36
- repositories = {}
37
- YAML.load(config).each do |source, orgs|
38
- orgs.each do |org, value|
39
- value.each do |name, settings|
40
- cfg = settings.is_a?(Hash) ? settings : {}
41
- repo = Object.const_get("CuttingEdge::#{source.capitalize}Repository").new(org, name, cfg.fetch('language', nil), cfg.fetch('locations', nil), cfg.fetch('branch', nil), cfg.fetch('api_token', nil))
42
- repo.dependency_types = cfg['dependency_types'].map {|dep| dep.to_sym} if cfg['dependency_types'].is_a?(Array)
43
- repositories["#{source}/#{org}/#{name}"] = repo
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 "Scheduling Jobs..."
78
+ puts 'Scheduling Jobs...'
56
79
  scheduler = Rufus::Scheduler.new
57
- scheduler.every('1h') do
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 "Running Workers a first time..."
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)
@@ -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
@@ -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.0.1'
9
- s.date = '2020-02-19'
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 =
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CuttingEdge
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1'
3
3
  end
@@ -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
- def worker_all_badges(repositories)
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 %r{/(.+)/(.+)/(.+)/info} do |source, org, name|
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].merge({:language => @repo.lang}).to_json # Todo: check whether value exists yet? If not, call worker / wait / timeout?
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 @repo.token && params[:token] == @repo.token
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
- halt 404, '404 Not Found' unless @repo = settings.repositories["#{source}/#{org}/#{name}"]
149
+ not_found unless @repo = settings.repositories["#{source}/#{org}/#{name}"]
74
150
  end
75
-
151
+
76
152
  end
77
153
  end