cutting_edge 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9345fa39664217f3d25636af4855abfa9f4e684237c0038fbeb4fa57e83ec40d
4
- data.tar.gz: de6eaa52e75463fed82b1aae4723e6685a80522086ed28cc3a8ded7e6b3189cb
3
+ metadata.gz: f2b2c4c5c7d23ff00b0f4124b7040aa7733b48b6474178f596d35358df8e779a
4
+ data.tar.gz: de40b5d1c93e556ab5387352cbc3cb9bf5d13b7e2f0db06ba044f7189d000889
5
5
  SHA512:
6
- metadata.gz: c866cf8788242847e16b65f0b8a21481b5b57df936241d9bdf68044d62d55083d12dc827f6eeedd4978716ad131a2ac7993ea2ad0f6b6a23a150dc35f4ca6359
7
- data.tar.gz: afcee66340cc2f542d45ab6bb4f5a5427d57c69ec7d925f49f22909cf2c0de2f767b8ecf8ab4b295dba6f514177309607ad1a185455f257a35ff40884b802652
6
+ metadata.gz: e26af96def69913fcb64680de7a45d1e5faa34f497994d5b7970f136c0d87eb6a4430fa8d68ccab031e7c77d5662778cd084714db74caf52cb41e90f7602e814
7
+ data.tar.gz: da2caeadbed7b997c22ecd0943ad97eed25996199d1355386c758d7d47ada429adde0384b1ee27bece5958b5ecd1c758362f1c1befa22470fd3db95447a9ff82
data/Dockerfile ADDED
@@ -0,0 +1,29 @@
1
+ FROM ruby:3.0.4-alpine AS builder
2
+
3
+ RUN apk add \
4
+ build-base \
5
+ git \
6
+ cmake \
7
+ libffi-dev
8
+
9
+ COPY Gemfile* /tmp/
10
+ COPY cutting_edge.gemspec* /tmp/
11
+ WORKDIR /tmp
12
+ RUN bundle install
13
+
14
+ WORKDIR /app
15
+ COPY . /app
16
+ RUN bundle exec rake install
17
+
18
+ FROM ruby:3.0.4-alpine
19
+
20
+ COPY --from=builder /usr/local/bundle/ /usr/local/bundle/
21
+
22
+ RUN apk add \
23
+ bash \
24
+ tzdata
25
+
26
+ VOLUME /cutting_edge
27
+ WORKDIR /cutting_edge
28
+ COPY docker-run.sh /docker-run.sh
29
+ ENTRYPOINT ["/docker-run.sh"]
data/Gemfile CHANGED
@@ -1,13 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'redis', require: false
4
+ gem 'thin', require: false
4
5
 
5
6
  group :development do
6
7
  gem 'rspec', '~> 3.9'
7
8
  gem 'simplecov'
9
+ gem 'simplecov-lcov', '~> 0.8.0'
8
10
  gem 'rack-test'
9
11
  end
10
12
 
11
- gem 'coveralls', '~>0.8.23', require: false
12
-
13
- gemspec
13
+ gemspec
data/HISTORY.md ADDED
@@ -0,0 +1,3 @@
1
+ # v0.2.1 / 2021-09-02
2
+
3
+ * Add ~= comparator and translate it to ~>. Resolves #66 (@bartkamphorst)
data/LATEST_CHANGES.md ADDED
@@ -0,0 +1,7 @@
1
+ # 0.3
2
+
3
+ * Added the `--redis` command line argument.
4
+ * Added Docker support.
5
+ * Use Redis on Heroku by default to avoid flakiness caused by Heroku's dynos.
6
+ * Change default branch name to `main`
7
+ * Do not mail when the diff is empty.
data/README.md CHANGED
@@ -1,11 +1,14 @@
1
1
  # CuttingEdge -- Simple, self-hosted dependency monitoring
2
2
 
3
- [![Build Status](https://travis-ci.org/repotag/cutting_edge.svg?branch=master)](https://travis-ci.org/repotag/cutting_edge)
4
- [![Coverage Status](https://coveralls.io/repos/github/repotag/cutting_edge/badge.svg?branch=master)](https://coveralls.io/github/repotag/cutting_edge?branch=master)
3
+ [![Ruby Build](https://github.com/repotag/cutting_edge/actions/workflows/test.yaml/badge.svg)](https://github.com/repotag/cutting_edge/actions/workflows/test.yaml)
4
+ [![Coverage Status](https://coveralls.io/repos/github/repotag/cutting_edge/badge.svg?branch=main)](https://coveralls.io/github/repotag/cutting_edge?branch=main)
5
5
  [![Cutting Edge Dependency Status](https://dometto-cuttingedge.herokuapp.com/github/repotag/cutting_edge/svg 'Cutting Edge Dependency Status')](https://dometto-cuttingedge.herokuapp.com/github/repotag/cutting_edge/info)
6
+ [![Docker Pulls](https://img.shields.io/docker/pulls/dometto/cuttingedge)](https://hub.docker.com/r/dometto/cuttingedge)
6
7
 
7
8
  CuttingEdge monitors the status of the dependencies of your projects and lets you know when any of them go out of date.
8
9
 
10
+ **View the web front end of a [live instance](https://dometto-cuttingedge.herokuapp.com/)**.
11
+
9
12
  ## Features
10
13
 
11
14
  * Generates badge images that you can include in your projects' Readme, like the one above!
@@ -21,8 +24,6 @@ CuttingEdge monitors the status of the dependencies of your projects and lets yo
21
24
  * Gitlab (both gitlab.com and [self-hosted instances](#Adding-self-hosted-repository-servers))
22
25
  * Gitea ([self-hosted](#Adding-self-hosted-repository-servers))
23
26
  * Both public and [private repositories](#Authorization-and-private-repositories)
24
-
25
- **View the web front end of a [live instance](https://dometto-cuttingedge.herokuapp.com/)**.
26
27
 
27
28
  ## Requirements
28
29
 
@@ -36,24 +37,19 @@ CuttingEdge is lightweight and easy to deploy:
36
37
 
37
38
  ## Installation
38
39
 
39
- Simply:
40
+ ### Using Docker
40
41
 
41
- ```
42
- $ gem install cutting_edge
43
- $ cutting_edge
44
- ```
42
+ To run CuttingEdge on port 4567 on the host machine, with config.rb and projects.yml in the current working directory, simply:
45
43
 
46
- Or run from source:
44
+ `docker pull dometto/cuttingedge`
45
+ `docker run -d --rm -p 4567:4567 -v $(pwd):/cutting_edge dometto/cuttingedge:main -c config.r`
47
46
 
48
- ```
49
- $ git clone https://github.com/repotag/cutting_edge.git
50
- $ cd cutting_edge
51
- $ bundle install
52
- $ bundle exec cutting_edge
53
- ```
47
+ (Instead of using `main`, you can also use a release tag, e.g. `dometto/cuttingedge:v0.2.1`.)
54
48
 
55
49
  Before running, define your repositories in [projects.yml](#projects-yml). You may also want to change some settings in [config.rb](#config-rb).
56
50
 
51
+ Also see our example [docker-compose](docker-compose.yml) file for an example of how to use CuttingEdge with [Redis as a datastore](#Using-Redis-and-other-data-stores) via Docker.
52
+
57
53
  ### Deploying on Heroku
58
54
 
59
55
  CuttingEdge runs out of the box on Heroku, and is lightweight enough to function on the Heroku free plan. This repository already contains the `Procfile` needed for deployment.
@@ -63,11 +59,14 @@ CuttingEdge runs out of the box on Heroku, and is lightweight enough to function
63
59
  Steps:
64
60
 
65
61
  1. Clone/fork this repository, as it already contains some settings (in `heroku.config.rb`) relevant to Heroku
66
- 1. Edit `projects.yml` and commit it to the repo
67
- 1. `heroku create my-cuttingedge`
68
- 1. `heroku config:add HEROKU_APP_NAME=my-cuttingedge`
69
- 1. `git push heroku master`
70
- 1. *Optional, if you want to receive [email notifications](#Email-Notifications)*:
62
+ 1. Edit `projects.yml` and commit it to the repo.
63
+ 1. `gem install bundler && bundle install`
64
+ 2. `git add Gemfile.lock && git commit -m "Commit Gemfile.lock for use on Heroku"
65
+ 3. `heroku create my-cuttingedge`
66
+ 4. `heroku config:add HEROKU_APP_NAME=my-cuttingedge`
67
+ 5. `heroku addons:create heroku-redis:hobby-dev -a my-cuttingedge` (using Redis is highly recommended on Heroku)
68
+ 6. `git push heroku master`
69
+ 7. *Optional, if you want to receive [email notifications](#Email-Notifications)*:
71
70
  * `heroku addons:create mailgun:starter`
72
71
  * `heroku config:add CUTTING_EDGE_MAIL_TO=mydependencies@mydependencymonitoring.com`
73
72
  * If you are on the free plan: [add your email addresses as Authorized Recipients](https://help.mailgun.com/hc/en-us/articles/217531258-Authorized-Recipients) in [Mailgun](https://app.mailgun.com/) (login via Heroku)
@@ -76,6 +75,26 @@ You may also want to set some [Heroku config variables](https://devcenter.heroku
76
75
 
77
76
  Note that Heroku switches off apps running on their free plan when they idle, so you may want to look at [this](https://medium.com/better-programming/keeping-my-heroku-app-alive-b19f3a8c3a82).
78
77
 
78
+ ### As a gem
79
+
80
+ Simply:
81
+
82
+ ```
83
+ $ gem install cutting_edge
84
+ $ cutting_edge
85
+ ```
86
+
87
+ Or run from source:
88
+
89
+ ```
90
+ $ git clone https://github.com/repotag/cutting_edge.git
91
+ $ cd cutting_edge
92
+ $ bundle install
93
+ $ bundle exec cutting_edge
94
+ ```
95
+
96
+ Before running, define your repositories in [projects.yml](#projects-yml). You may also want to change some settings in [config.rb](#config-rb).
97
+
79
98
  ## Usage
80
99
 
81
100
  When your instance of CuttingEdge is running, you can visit the landing page by pointing your browser to the root URL of the app. Locally, it is by default accessible at:
@@ -106,7 +125,7 @@ This will make CuttingEdge monitor the GitHub project `my_org/my_project`. You c
106
125
  * `auth_token`: see [here](#Authorization-and-private-repositories)
107
126
  * `hide`: see [here](#Hide-repositories)
108
127
  * `locations`: use to change the default path to dependency definition files. For instance, for a Ruby project, CuttingEdge will by default try to monitor `Gemfile` and `my_project.gemspec`. You can override this with `language: [Gemfile, alternative/file.gemspec]`
109
- * `branch`: use a different branch than the default `master`
128
+ * `branch`: use a different branch than the default `main`
110
129
  * `email`:
111
130
  * disable email notifications for a single project by setting this to `false`
112
131
  * use a non-default address delivery address for this project by setting this to e.g. `myproject@mydependencymonitoring.com`
@@ -207,13 +226,15 @@ If you don't want to expose information about a project in (**such as an [API to
207
226
  module CuttingEdge
208
227
  require './lib/cutting_edge/repo.rb'
209
228
  REPOSITORIES = {
210
- "gitlab/#{ENV['SECRET_REPO1_ORG']}/#{ENV['SECRET_REPO1_NAME']}" => GitlabRepository.new(org: ENV['SECRET_REPO1_ORG'], name: ENV['SECRET_REPO1_NAME'], auth_token: ENV['SECRET_REPO1_AUTH_TOKEN'], hide: ENV['SECRET_REPO1_HIDE_TOKEN'])
229
+ "gitlab/#{ENV['SECRET_REPO1_ORG']}/#{ENV['SECRET_REPO1_NAME']}" => GitlabRepository.new(org: ENV['SECRET_REPO1_ORG'], name: ENV['SECRET_REPO1_NAME'], auth_token: ENV['SECRET_REPO1_AUTH_TOKEN'], hide: ENV['SECRET_REPO1_HIDE_TOKEN'], email: 'myemail@mydomain.org')
211
230
  }
212
231
  end
213
232
  ```
214
233
 
215
234
  This approach is especially useful on Heroku, where you can use [Heroku config variables](https://devcenter.heroku.com/articles/config-vars).
216
235
 
236
+ **NB: When adding repositories in config.rb, you must explicitly set the email attribute (or else email will be considered disabled for the repo).**
237
+
217
238
  ### Hide Repositories
218
239
 
219
240
  You may want the name and dependency monitoring information for private repositories (see above) not to be visible on the internet. To achieve this, you can use `hide: token` in `projects.yml`:
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'date'
3
+ require 'tempfile'
3
4
  require 'rspec/core/rake_task'
4
5
 
5
6
  task :default => :rspec
@@ -26,6 +27,14 @@ def version
26
27
  line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
27
28
  end
28
29
 
30
+ def latest_changes_file
31
+ 'LATEST_CHANGES.md'
32
+ end
33
+
34
+ def history_file
35
+ 'HISTORY.md'
36
+ end
37
+
29
38
  # assumes x.y.z all digit version
30
39
  def next_version
31
40
  # x.y.z
@@ -86,14 +95,15 @@ end
86
95
 
87
96
  desc 'Create a release build and push to rubygems'
88
97
  task :release => :build do
89
- unless `git branch` =~ /^\* master$/
90
- puts "You must be on the master branch to release!"
98
+ unless `git branch` =~ /^\* main$/
99
+ puts "You must be on the main branch to release!"
91
100
  exit!
92
101
  end
102
+ Rake::Task[:changelog].execute
93
103
  sh "git commit --allow-empty -a -m 'Release #{version}'"
94
- sh "git pull --rebase origin master"
104
+ sh "git pull --rebase origin main"
95
105
  sh "git tag v#{version}"
96
- sh "git push origin master"
106
+ sh "git push origin main"
97
107
  sh "git push origin v#{version}"
98
108
  sh "gem push pkg/#{name}-#{version}.gem"
99
109
  end
@@ -152,3 +162,43 @@ task :validate do
152
162
  exit!
153
163
  end
154
164
  end
165
+
166
+ desc 'Build changelog'
167
+ task :changelog do
168
+ [latest_changes_file, history_file].each do |f|
169
+ unless File.exists?(f)
170
+ puts "#{f} does not exist but is required to build a new release."
171
+ exit!
172
+ end
173
+ end
174
+
175
+ latest_changes = File.open(latest_changes_file)
176
+ version_pattern = "# #{version}"
177
+
178
+ if !`grep "#{version_pattern}" #{history_file}`.empty?
179
+ puts "#{version} is already described in #{history_file}"
180
+ exit!
181
+ end
182
+
183
+ begin
184
+ unless latest_changes.readline.chomp! =~ %r{#{version_pattern}}
185
+ puts "#{latest_changes_file} should begin with '#{version_pattern}'"
186
+ exit!
187
+ end
188
+ rescue EOFError
189
+ puts "#{latest_changes_file} is empty!"
190
+ exit!
191
+ end
192
+
193
+ body = latest_changes.read
194
+ body.scan(/\s*#\s+\d\.\d.*/) do |match|
195
+ puts "#{latest_changes_file} may not contain multiple markdown headers!"
196
+ exit!
197
+ end
198
+
199
+ temp = Tempfile.new
200
+ temp.puts("#{version_pattern} / #{date}\n#{body}\n")
201
+ temp.close
202
+ `cat #{history_file} >> #{temp.path}`
203
+ `cat #{temp.path} > #{history_file}`
204
+ end
data/bin/cutting_edge CHANGED
@@ -4,6 +4,7 @@ require 'yaml'
4
4
  require 'rufus-scheduler'
5
5
  require 'optparse'
6
6
  require 'semantic_logger'
7
+ require 'moneta'
7
8
 
8
9
  module CuttingEdge
9
10
  REFRESH_SCHEDULE = '1h'
@@ -42,6 +43,10 @@ opts = OptionParser.new do |opts|
42
43
  opts.on('-c', '--config [FILE]', 'Specify path to a .rb configuration file. Default: config.rb') do |file|
43
44
  options[:config] = file || 'config.rb'
44
45
  end
46
+
47
+ opts.on('-r', '--redis [URL]', 'Use Redis as a datastore. Optionally specify the Redis URL. Default URL: `redis://localhost/.`') do |url|
48
+ ::CuttingEdge::STORE = ::Moneta.new(:Redis, url: (url || 'redis://localhost/'))
49
+ end
45
50
  end
46
51
 
47
52
  begin
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.2'
9
- s.date = '2020-12-05'
8
+ s.version = '0.3'
9
+ s.date = '2022-10-15'
10
10
  s.license = 'GPL-3.0-only'
11
11
 
12
12
  s.summary = 'Self-hosted dependency monitoring, including shiny badges.'
@@ -22,8 +22,8 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_dependency 'gemnasium-parser', '~> 0.1.9'
24
24
  s.add_dependency 'hashdiff', '~> 1.0'
25
- s.add_dependency 'http', '~> 4.3'
26
- s.add_dependency 'sucker_punch', '~> 2.1'
25
+ s.add_dependency 'http', '~> 5.0'
26
+ s.add_dependency 'sucker_punch', '~> 3.0'
27
27
  s.add_dependency 'sinatra', '~> 2.0'
28
28
  s.add_dependency 'moneta', '~> 1.2'
29
29
  s.add_dependency 'rufus-scheduler', '~> 3.6'
@@ -33,8 +33,10 @@ Gem::Specification.new do |s|
33
33
 
34
34
  # = MANIFEST =
35
35
  s.files = %w[
36
+ Dockerfile
36
37
  Gemfile
37
- Gemfile.lock
38
+ HISTORY.md
39
+ LATEST_CHANGES.md
38
40
  LICENSE
39
41
  Procfile
40
42
  README.md
@@ -42,6 +44,8 @@ Gem::Specification.new do |s|
42
44
  bin/cutting_edge
43
45
  config.rb
44
46
  cutting_edge.gemspec
47
+ docker-compose.yml
48
+ docker-run.sh
45
49
  heroku.config.rb
46
50
  lib/cutting_edge.rb
47
51
  lib/cutting_edge/app.rb
@@ -0,0 +1,23 @@
1
+ # Example of a simple docker-compose file to run CuttingEdge with a redis datastore
2
+ # Simply run `docker-compose up`
3
+ version: '3.8'
4
+ services:
5
+ cache:
6
+ image: redis:7.0.5-alpine
7
+ restart: always
8
+ ports:
9
+ - '6379:6379'
10
+ cuttingedge:
11
+ image: dometto/cuttingedge:main
12
+ environment:
13
+ REDIS_HOST: cache
14
+ command:
15
+ - -r redis://cache
16
+ depends_on:
17
+ - cache
18
+ ports:
19
+ - 4567:4567
20
+ links:
21
+ - cache
22
+ volumes:
23
+ - ./:/cutting_edge
data/docker-run.sh ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ exec cutting_edge $@
data/heroku.config.rb CHANGED
@@ -4,10 +4,19 @@ module CuttingEdge
4
4
  SERVER_HOST = "#{ENV['HEROKU_APP_NAME']}.herokuapp.com" # At what domain is this CuttingEdge instance running?
5
5
  SERVER_URL = "https://#{SERVER_HOST}"
6
6
  MAIL_TO = ENV['CUTTING_EDGE_MAIL_TO'] if ENV['CUTTING_EDGE_MAIL_TO']
7
-
7
+ if ENV['REDIS_TLS_URL']
8
+ require 'moneta'
9
+ require 'openssl'
10
+ STORE = ::Moneta.new(:Redis,
11
+ url: ENV['REDIS_TLS_URL'],
12
+ ssl_params: {
13
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
14
+ }
15
+ )
16
+ end
8
17
  # Your additional configuration goes here.
9
18
  # 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
19
+ # https://github.com/repotag/cutting_edge/blob/main/README.md#Defining-repositories-in-configrb
11
20
  end
12
21
 
13
22
  # Needed to write to Heroku logs.
@@ -4,7 +4,7 @@ require 'http'
4
4
  class PythonLang < Language
5
5
  # For Requirements.txt
6
6
  # See https://iscompatible.readthedocs.io/en/latest/
7
- COMPARATORS = />=|>|<=|<|==/
7
+ COMPARATORS = />=|>|<=|<|==|~=/
8
8
  VERSION_NUM = /\d[\.\w]*/
9
9
  SUFFIX_OPTION = /\s*(\[.*\])?/
10
10
  NAME = /[^,]+/
@@ -55,6 +55,7 @@ class PythonLang < Language
55
55
  name, first_comp, first_version, _ignore, second_comp, second_version = match.captures
56
56
  first_comp = '=' if first_comp == '=='
57
57
  second_comp = '=' if second_comp == '=='
58
+ first_comp = '~>' if first_comp == '~='
58
59
  dep = Gem::Dependency.new(name.strip, "#{first_comp} #{first_version}")
59
60
  dep.requirement.concat(["#{second_comp} #{second_version}"]) if second_comp && second_version
60
61
  else
@@ -92,7 +92,7 @@ module CuttingEdge
92
92
  @org = org
93
93
  @name = name
94
94
  @auth_token = auth_token
95
- @branch = branch || 'master'
95
+ @branch = branch || 'main'
96
96
  @hidden = hide
97
97
  @lang = lang || DEFAULT_LANG
98
98
  @contact_email = email
@@ -124,6 +124,7 @@
124
124
  This is <a href="<%= url %>">CuttingEdge</a> informing you that the dependency status for <a href="<%= "#{url}/#{project}/info" %>"><%= project %></a> has changed.
125
125
  </p>
126
126
  <% specs[:locations].each do |filename, spec| %>
127
+ <% next if spec.values.flatten.empty? %>
127
128
  <p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">
128
129
  In <b><%= filename %></b>:
129
130
  <% spec.each do |type, dependencies|
@@ -146,7 +146,7 @@ class DependencyWorker < GenericWorker
146
146
  begin
147
147
  response = HTTP.headers(@provider.headers(@auth_token)).get(url)
148
148
  response.status == 200 ? response.to_s : nil
149
- rescue HTTP::TimeoutError => e
149
+ rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError => e
150
150
  log_info("Encountered error when fetching latest version of #{url}: #{e.class} #{e.message}")
151
151
  end
152
152
  end
@@ -22,6 +22,8 @@ class MailWorker < GenericWorker
22
22
  diff = {}
23
23
  end
24
24
 
25
+ return if diff.empty?
26
+
25
27
  Mail.deliver do
26
28
  from "CuttingEdge <#{CuttingEdge::MAIL_FROM}>"
27
29
  to to_addr
data/lib/cutting_edge.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CuttingEdge
2
- VERSION = '0.2'
2
+ VERSION = '0.3'
3
3
  end
data/projects.yml CHANGED
@@ -16,6 +16,7 @@ github:
16
16
  flask-dance:
17
17
  language: python
18
18
  email: false
19
+ branch: main
19
20
  rust-lang:
20
21
  crates.io:
21
22
  language: rust
@@ -20,7 +20,19 @@ describe MailWorker do
20
20
  it 'returns nil' do
21
21
  expect(worker.perform(identifier, test_email)).to eq nil
22
22
  end
23
- end
23
+ end
24
+
25
+ it 'does not list empty locations' do
26
+ dependencies[:locations]['Gemfile'] = DependencyWorker::EMPTY_STATUS_HASH
27
+ params = {
28
+ project: identifier,
29
+ url: CuttingEdge::SERVER_URL,
30
+ diff: {},
31
+ specs: dependencies
32
+ }
33
+ result = ERB.new(CuttingEdge::MAIL_TEMPLATE).result_with_hash(params)
34
+ expect(result).to_not include('Gemfile')
35
+ end
24
36
 
25
37
  context 'with valid dependencies' do
26
38
  before(:each) {
@@ -35,7 +47,7 @@ describe MailWorker do
35
47
  expect(worker.perform(identifier, nil)).to eq nil
36
48
  end
37
49
 
38
- it 'handles nil for diff' do
50
+ it 'do not mail for empty diff' do
39
51
  params = {
40
52
  project: identifier,
41
53
  url: CuttingEdge::SERVER_URL,
@@ -43,7 +55,7 @@ describe MailWorker do
43
55
  specs: dependencies
44
56
  }
45
57
  expect(worker).to receive(:delete_from_store).with("diff-#{identifier}").and_return(nil)
46
- expect_any_instance_of(ERB).to receive(:result_with_hash).with(params).and_call_original
58
+ expect_any_instance_of(ERB).not_to receive(:result_with_hash)
47
59
  worker.perform(identifier, test_email)
48
60
  end
49
61
 
@@ -74,6 +86,16 @@ describe MailWorker do
74
86
  expect(html_body).to include('<li>rake ~> 12.3, >= 12.3.3 (latest: 13.0.1)</li>')
75
87
  expect(html_body).to include('<li style="color:green;">foobar = 1.0 (latest: 1.0)</li>')
76
88
  end
89
+
90
+ context 'with multiple email' do
91
+ let(:test_email) { ['test1@test.org', 'test2@test.org'] }
92
+
93
+ it 'sends an update mail' do
94
+ worker.perform(identifier, test_email)
95
+ mail = Mail::TestMailer.deliveries.first
96
+ expect(mail.to).to eq test_email
97
+ end
98
+ end
77
99
  end
78
100
  end
79
101
  end
@@ -5,6 +5,7 @@ requests-oauthlib>=1.0.0 [PDF]
5
5
  -e svn+http://myrepo/svn/MyApp#egg=MyApp
6
6
  Flask>=0.7
7
7
  urlobject==1.0
8
+ email-validator ~= 1.1.2
8
9
  six
9
10
  EOF
10
11
 
@@ -44,6 +45,7 @@ describe PythonLang do
44
45
  'requests-oauthlib': Gem::Version.new('1.3.0'),
45
46
  'Flask': Gem::Version.new('1.1.2'),
46
47
  'urlobject': Gem::Version.new('2.4.3'),
48
+ 'email-validator': Gem::Version.new('1.1.2'),
47
49
  'six': Gem::Version.new('1.15.0'),
48
50
  }
49
51
  }
@@ -84,7 +86,7 @@ describe PythonLang do
84
86
  expect(PythonLang).to receive(:latest_version).and_return(*requirements_latest_versions.values)
85
87
  result = PythonLang.parse_file('requirements.txt', REQUIREMENT_TXT)
86
88
  expect(result).to be_a Array
87
- expect(result.length).to eq 6
89
+ expect(result.length).to eq 7
88
90
  result.each do |dep, version|
89
91
  expect(dep).to be_a Gem::Dependency
90
92
  expect(dep.type).to eq :runtime
data/spec/repo_spec.rb CHANGED
@@ -12,6 +12,11 @@ describe CuttingEdge::Repository do
12
12
  expect(CuttingEdge::Repository.headers(nil)).to eq ({})
13
13
  end
14
14
 
15
+ it 'can take an array of email addresses' do
16
+ repo = CuttingEdge::GithubRepository.new(org: 'org', name: 'name', email: ['test1@test.org', 'test2@test2.org'])
17
+ expect(repo.contact_email).to eq ['test1@test.org', 'test2@test2.org']
18
+ end
19
+
15
20
  context 'GitHub' do
16
21
  it 'has a headers method' do
17
22
  expect(CuttingEdge::GithubRepository.headers(nil)).to eq ({:accept => 'application/vnd.github.v3.raw'})
@@ -22,7 +27,7 @@ describe CuttingEdge::Repository do
22
27
  expect(CuttingEdge::GithubRepository).to_not be_nil
23
28
  github = CuttingEdge::GithubRepository.new(org: 'org', name: 'name')
24
29
  expect(github.source).to eq 'github'
25
- expect(github.url_for_file('file')).to eq 'https://api.github.com/repos/org/name/contents/file?ref=master'
30
+ expect(github.url_for_file('file')).to eq 'https://api.github.com/repos/org/name/contents/file?ref=main'
26
31
  expect(github.url_for_project).to eq 'https://github.com/org/name'
27
32
  end
28
33
  end
@@ -35,7 +40,7 @@ describe CuttingEdge::Repository do
35
40
  expect(CuttingEdge::GitlabRepository.headers('token')).to eq ({:authorization => 'Bearer token'})
36
41
  gitlab = CuttingEdge::GitlabRepository.new(org: 'org', name: 'name')
37
42
  expect(gitlab.source).to eq 'gitlab'
38
- expect(gitlab.url_for_file('file')).to eq 'https://gitlab.com/api/v4/projects/org%2fname/repository/files/file/raw?ref=master'
43
+ expect(gitlab.url_for_file('file')).to eq 'https://gitlab.com/api/v4/projects/org%2fname/repository/files/file/raw?ref=main'
39
44
  expect(gitlab.url_for_project).to eq 'https://gitlab.com/org/name'
40
45
  end
41
46
 
@@ -45,7 +50,7 @@ describe CuttingEdge::Repository do
45
50
  expect(defined?(CuttingEdge::GiteaRepository)).to_not be_nil
46
51
  gitea = CuttingEdge::GiteaRepository.new(org: 'org', name: 'name')
47
52
  expect(gitea.source).to eq 'gitea'
48
- expect(gitea.url_for_file('file')).to eq 'https://mydependencymonitoring.com/api/v1/repos/org/name/raw/master/file'
53
+ expect(gitea.url_for_file('file')).to eq 'https://mydependencymonitoring.com/api/v1/repos/org/name/raw/main/file'
49
54
  expect(gitea.url_for_project).to eq 'https://mydependencymonitoring.com/org/name'
50
55
  end
51
56
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,14 @@
1
1
  require 'simplecov'
2
+ require 'simplecov-lcov'
2
3
  require 'fixtures'
3
4
  require 'rack/test'
4
5
 
5
- if ENV['TRAVIS']
6
- require 'coveralls'
7
- Coveralls.wear!
6
+ if ENV['CI']
7
+ SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
8
+ SimpleCov::Formatter::LcovFormatter.config.single_report_path = 'coverage/lcov.info'
9
+ SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
8
10
  end
11
+ SimpleCov.start
9
12
 
10
13
  ENV['RACK_ENV'] = 'test'
11
14
 
@@ -116,4 +119,4 @@ RSpec.configure do |config|
116
119
  config.include Rack::Test::Methods
117
120
  config.include ::CuttingEdgeHelpers
118
121
  config.include ::WorkerHelpers
119
- end
122
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cutting_edge
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dawa Ometto
8
8
  - Bart Kamphorst
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-05 00:00:00.000000000 Z
12
+ date: 2022-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gemnasium-parser
@@ -45,28 +45,28 @@ dependencies:
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '4.3'
48
+ version: '5.0'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '4.3'
55
+ version: '5.0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: sucker_punch
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '2.1'
62
+ version: '3.0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '2.1'
69
+ version: '3.0'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: sinatra
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -158,8 +158,10 @@ executables:
158
158
  extensions: []
159
159
  extra_rdoc_files: []
160
160
  files:
161
+ - Dockerfile
161
162
  - Gemfile
162
- - Gemfile.lock
163
+ - HISTORY.md
164
+ - LATEST_CHANGES.md
163
165
  - LICENSE
164
166
  - Procfile
165
167
  - README.md
@@ -167,6 +169,8 @@ files:
167
169
  - bin/cutting_edge
168
170
  - config.rb
169
171
  - cutting_edge.gemspec
172
+ - docker-compose.yml
173
+ - docker-run.sh
170
174
  - heroku.config.rb
171
175
  - lib/cutting_edge.rb
172
176
  - lib/cutting_edge/app.rb
@@ -212,7 +216,7 @@ homepage: http://github.com/repotag/cutting_edge
212
216
  licenses:
213
217
  - GPL-3.0-only
214
218
  metadata: {}
215
- post_install_message:
219
+ post_install_message:
216
220
  rdoc_options: []
217
221
  require_paths:
218
222
  - lib
@@ -227,8 +231,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
231
  - !ruby/object:Gem::Version
228
232
  version: '0'
229
233
  requirements: []
230
- rubygems_version: 3.0.3
231
- signing_key:
234
+ rubygems_version: 3.1.4
235
+ signing_key:
232
236
  specification_version: 2
233
237
  summary: Self-hosted dependency monitoring, including shiny badges.
234
238
  test_files: []
data/Gemfile.lock DELETED
@@ -1,130 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cutting_edge (0.2)
5
- gemnasium-parser (~> 0.1.9)
6
- hashdiff (~> 1.0)
7
- http (~> 4.3)
8
- mail (~> 2.7)
9
- moneta (~> 1.2)
10
- rufus-scheduler (~> 3.6)
11
- sinatra (~> 2.0)
12
- sinatra-logger (~> 0.3)
13
- sucker_punch (~> 2.1)
14
- toml-rb (~> 2.0)
15
-
16
- GEM
17
- remote: https://rubygems.org/
18
- specs:
19
- addressable (2.7.0)
20
- public_suffix (>= 2.0.2, < 5.0)
21
- citrus (3.0.2)
22
- concurrent-ruby (1.1.7)
23
- coveralls (0.8.23)
24
- json (>= 1.8, < 3)
25
- simplecov (~> 0.16.1)
26
- term-ansicolor (~> 1.3)
27
- thor (>= 0.19.4, < 2.0)
28
- tins (~> 1.6)
29
- diff-lcs (1.4.4)
30
- docile (1.3.2)
31
- domain_name (0.5.20190701)
32
- unf (>= 0.0.5, < 1.0.0)
33
- et-orbi (1.2.4)
34
- tzinfo
35
- ffi (1.13.1)
36
- ffi-compiler (1.0.1)
37
- ffi (>= 1.0.0)
38
- rake
39
- fugit (1.4.0)
40
- et-orbi (~> 1.1, >= 1.1.8)
41
- raabro (~> 1.4)
42
- gemnasium-parser (0.1.9)
43
- hashdiff (1.0.1)
44
- http (4.4.1)
45
- addressable (~> 2.3)
46
- http-cookie (~> 1.0)
47
- http-form_data (~> 2.2)
48
- http-parser (~> 1.2.0)
49
- http-cookie (1.0.3)
50
- domain_name (~> 0.5)
51
- http-form_data (2.3.0)
52
- http-parser (1.2.1)
53
- ffi-compiler (>= 1.0, < 2.0)
54
- json (2.3.1)
55
- mail (2.7.1)
56
- mini_mime (>= 0.1.1)
57
- mini_mime (1.0.2)
58
- moneta (1.4.1)
59
- mustermann (1.1.1)
60
- ruby2_keywords (~> 0.0.1)
61
- public_suffix (4.0.6)
62
- raabro (1.4.0)
63
- rack (2.2.3)
64
- rack-protection (2.1.0)
65
- rack
66
- rack-test (1.1.0)
67
- rack (>= 1.0, < 3)
68
- rake (13.0.1)
69
- redis (4.2.2)
70
- rspec (3.10.0)
71
- rspec-core (~> 3.10.0)
72
- rspec-expectations (~> 3.10.0)
73
- rspec-mocks (~> 3.10.0)
74
- rspec-core (3.10.0)
75
- rspec-support (~> 3.10.0)
76
- rspec-expectations (3.10.0)
77
- diff-lcs (>= 1.2.0, < 2.0)
78
- rspec-support (~> 3.10.0)
79
- rspec-mocks (3.10.0)
80
- diff-lcs (>= 1.2.0, < 2.0)
81
- rspec-support (~> 3.10.0)
82
- rspec-support (3.10.0)
83
- ruby2_keywords (0.0.2)
84
- rufus-scheduler (3.6.0)
85
- fugit (~> 1.1, >= 1.1.6)
86
- semantic_logger (4.7.3)
87
- concurrent-ruby (~> 1.0)
88
- simplecov (0.16.1)
89
- docile (~> 1.1)
90
- json (>= 1.8, < 3)
91
- simplecov-html (~> 0.10.0)
92
- simplecov-html (0.10.2)
93
- sinatra (2.1.0)
94
- mustermann (~> 1.0)
95
- rack (~> 2.2)
96
- rack-protection (= 2.1.0)
97
- tilt (~> 2.0)
98
- sinatra-logger (0.3.2)
99
- semantic_logger
100
- sinatra
101
- sucker_punch (2.1.2)
102
- concurrent-ruby (~> 1.0)
103
- sync (0.5.0)
104
- term-ansicolor (1.7.1)
105
- tins (~> 1.0)
106
- thor (1.0.1)
107
- tilt (2.0.10)
108
- tins (1.26.0)
109
- sync
110
- toml-rb (2.0.1)
111
- citrus (~> 3.0, > 3.0)
112
- tzinfo (2.0.2)
113
- concurrent-ruby (~> 1.0)
114
- unf (0.1.4)
115
- unf_ext
116
- unf_ext (0.0.7.7)
117
-
118
- PLATFORMS
119
- ruby
120
-
121
- DEPENDENCIES
122
- coveralls (~> 0.8.23)
123
- cutting_edge!
124
- rack-test
125
- redis
126
- rspec (~> 3.9)
127
- simplecov
128
-
129
- BUNDLED WITH
130
- 2.1.4