Add the basic Canary app structure

This is derped along without any tests hard enough because I don't feel like
spending the time right now to come up with API shims for Sentry, whose data
types are nested AF.
This commit is contained in:
R. Tyler Croy 2017-09-03 12:17:45 -07:00
parent 01f52e7ba0
commit 78719b0fce
No known key found for this signature in database
GPG Key ID: 1426C7DC3F51E16F
20 changed files with 361 additions and 1 deletions

2
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.sw*
*.gem
*.rbc
/.config
@ -48,3 +49,4 @@ build-iPhoneSimulator/
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
vendor/

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM ruby:2.3-alpine
ARG APP_DIR=/webapp
RUN mkdir -p ${APP_DIR}/vendor
WORKDIR ${APP_DIR}
ADD vendor/ ${APP_DIR}/vendor/
ENV GEM_HOME=${APP_DIR}/vendor/gems
ENV BUNDLE_PATH=${APP_DIR}/vendor/gems
ENV BUNDLE_APP_CONFIG=${APP_DIR}/vendor/gems/.bundle
ENV BUNDLE_DISABLE_SHARED_GEMS=true
ADD Gemfile* ${APP_DIR}/
ADD app.rb ${APP_DIR}/
ADD config.ru ${APP_DIR}/
ADD views ${APP_DIR}/views/
ADD assets ${APP_DIR}/assets/
CMD bundle exec rackup -o 0.0.0.0

10
Gemfile Normal file
View File

@ -0,0 +1,10 @@
source 'https://rubygems.org'
gem 'haml'
gem 'sinatra'
gem 'sentry-raven'
gem 'sentry-api'
group :test do
gem 'rspec'
end

59
Gemfile.lock Normal file
View File

@ -0,0 +1,59 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.3)
faraday (0.13.1)
multipart-post (>= 1.2, < 3)
haml (5.0.2)
temple (>= 0.8.0)
tilt
httmultiparty (0.3.16)
httparty (>= 0.7.3)
mimemagic
multipart-post
httparty (0.15.6)
multi_xml (>= 0.5.2)
mimemagic (0.3.2)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (1.0.1)
rack (2.0.3)
rack-protection (2.0.0)
rack
rspec (3.6.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-core (3.6.0)
rspec-support (~> 3.6.0)
rspec-expectations (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-support (3.6.0)
sentry-api (0.3.3)
httmultiparty (~> 0.3.16)
sentry-raven (2.6.3)
faraday (>= 0.7.6, < 1.0)
sinatra (2.0.0)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.0)
tilt (~> 2.0)
temple (0.8.0)
tilt (2.0.8)
PLATFORMS
ruby
DEPENDENCIES
haml
rspec
sentry-api
sentry-raven
sinatra
BUNDLED WITH
1.15.3

21
Makefile Normal file
View File

@ -0,0 +1,21 @@
all: check container
check: depends spec
spec:
./scripts/ruby bundle exec rspec -c
depends: Gemfile
./scripts/ruby bundle install
run: depends
./scripts/ruby bundle exec rackup -o 0.0.0.0
container: depends Dockerfile
docker build -t rtyler/codevalet-canary .
clean:
rm -rf vendor
.PHONY: all depends clean run check container spec

View File

@ -2,7 +2,7 @@
image::https://codevalet.io/u/codevalet/job/CodeValet/job/canary/job/master/badge/icon[Build Status, link=http://codevalet.codevalet.io/blue/organizations/jenkins/CodeValet%2Fcanary/activit://codevalet.io/u/codevalet/blue/organizations/jenkins/CodeValet%2Fcanary/activity]
image::https://github.com/codevalet/canary/raw/master/assets/songbird-128.png[Grace]
image::https://github.com/codevalet/canary/raw/master/assets/images/songbird-128.png[Grace]
Canary is the service providing public status and information for
link:http://codevalet.io[Code Valet].

57
app.rb Normal file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env ruby
require 'haml'
require 'raven'
require 'sinatra/base'
require 'sentry-api'
module CodeValet
module Canary
class App < Sinatra::Base
enable :sessions
enable :raise_errors
disable :show_exceptions
set :public_folder, File.dirname(__FILE__) + '/assets'
SentryApi.configure do |config|
config.endpoint = 'https://app.getsentry.com/api/0'
config.auth_token = ENV['SENTRY_API_TOKEN']
config.default_org_slug = 'codevalet'
end
get '/' do
projects = []
begin
projects = SentryApi.projects
rescue StandardError => exc
Raven.capture_exception(exc)
end
haml :index,
:layout => :_base,
:locals => {
:projects => projects,
}
end
get '/issue/:id' do
issue = nil
events = []
begin
issue = SentryApi.issue(params['id'])
events = SentryApi.issue_events(params['id'])
rescue StandardError => exc
Raven.capture_exception(exc)
end
haml :issue,
:layout => :_base,
:locals => {
:issue => issue,
:events => events,
}
end
end
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
assets/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/images/github-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

12
config.ru Normal file
View File

@ -0,0 +1,12 @@
$LOAD_PATH << File.dirname(__FILE__)
ENV['RACK_ENV'] ||= 'development'
require 'app'
require 'raven'
use Rack::Static, :urls => ["/css", "/img", "/js"], :root => "public"
use Raven::Rack
run CodeValet::Canary::App

14
scripts/ruby Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
exec docker run --rm -ti \
-u $(id -u):$(id -g) \
-w ${PWD} \
-v ${PWD}:${PWD} \
-e LANG=C.UTF-8 \
-e GEM_HOME=${PWD}/vendor/gems \
-e BUNDLE_PATH=${PWD}/vendor/gems \
-e BUNDLE_APP_CONFIG=${PWD}/vendor/gems/.bundle \
-e BUNDLE_DISABLE_SHARED_GEMS=true \
-e SENTRY_API_TOKEN=$SENTRY_API_TOKEN \
-p 9292:9292 \
ruby:2.3 $@

69
views/_base.haml Normal file
View File

@ -0,0 +1,69 @@
!!! XML
!!!
%html
%head
%meta{:name => 'referrer', :content => 'no-referrer'}/
%link{:rel => 'stylesheet',
:href => 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css',
:integrity => 'sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ',
:crossorigin => 'anonymous'}/
%script{:src => 'https://code.jquery.com/jquery-3.2.1.slim.min.js',
:integrity => 'sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN',
:crossorigin => 'anonymous'}
%script{:src => 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js',
:crossorigin => 'anonymous',
:integrity => 'sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn'}
%meta{:charset => 'utf-8'}/
%meta{:name => 'viewport',
:content => 'width=device-width, initial-scale=1, shrink-to-fit=no'}/
%link{:rel => 'icon', :type => 'image/ico', :href => '/images/favicon.ico'}/
%title
Code Valet - Canary
%body
%nav.navbar.navbar-inverse.bg-warning.navbar-toggleable
%a.navbar-brand{:href => '/'}
%img{:src => '/images/songbird-128.png',
:width => '50', :height => '50', :alt => 'Grace the Canary in the Code Mine'}/
Canary
.navbar-collapse
.navbar-nav
%a.nav-item.nav-link{:href => 'https://codevalet.io/'}
Return to Code Valet
.container.mt-5
= yield
%hr/
.container
.row
.col-md-6
%p
&copy; 2017
%a{:href => 'https://github.com/rtyler'}
R. Tyler Croy.
.col-md-6
%p.text-right
%a{:href => 'https://twitter.com/codevalet'}
%img{:src => '/images/twitter-32.png',
:alt => 'Code Valet on Twitter',
:title => 'Code Valet on Twitter'}/
%a{:href => 'https://github.com/codevalet'}
%img{:src => '/images/github-32.png',
:alt => 'Code Valet on GitHub',
:title => 'Code Valet on GitHub'}/
.row
%p
Jenkins&reg; is a registered trademark of
%a{:href => 'http://spi-inc.org'}
Software in the Public Interest, Inc.
:javascript
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-104976589-1', 'auto');
ga('send', 'pageview');

46
views/index.haml Normal file
View File

@ -0,0 +1,46 @@
.container
.row
.col-md-12
%h2
Meet Canary
%img{:src => '/images/songbird-128.png',
:title => 'Grace the Canary in the Code Mine',
:align => :right}
%p
Canary is part of
%a{:href => 'https://codevalet.io/', :target => '_blank'}
Code Valet
which provides radically transparent feedback for the service's
operation. Canary allows developers to triage and understand issues
affecting Code Valet, or one of its components.
- projects.auto_paginate do |project|
.row
.col-md-12
%h3= project.name
%p
- events = SentryApi.project_issues(project.slug)
- unless events.size > 0
No recent events (yay).
- else
- events.each do |event|
- badge = 'danger'
- if event.level != 'error'
- badge = event.level
.row
.col-lg-10
%strong
= event.title
.mb-2.text-muted
%span.badge{:class => "badge-#{badge}"}
= event.count
= event.culprit
%p
%a{:href => "issue/#{event.id}"}
View
&middot;
%a{:href => event.permalink, :target => '_blank'}
View in Sentry
%hr/

49
views/issue.haml Normal file
View File

@ -0,0 +1,49 @@
.container
.row
.col-md-12
- unless events
Something went wrong when rendering this page :(
- else
%h2
= issue.title
%h3.text-muted
= issue.culprit
.row
.col-md-12
%small
There are
%strong
= events.size
events associated with this issue.
- events.each do |event|
.row
.col-md-12
- event.tags.each do |tag|
%span.badge.badge-info
#{tag['key']}:#{tag['value']}
- event.entries.each do |entry|
/ #{entry.inspect}
- if entry['type'] == 'message'
%p
- if entry['data']['formatted']
= entry['data']['formatted']
- else
= entry['data']['message']
- if entry['type'] == 'exception'
- entry['data']['values'].each do |val|
%ul.list-unstyled
- val['stacktrace']['frames'].reverse_each do |frame|
%li
%div.m-1
%strong
= frame['module']
in
%strong
= frame['function']
at line #{frame['lineNo']} of
%code
= frame['absPath']
- break