Compare commits

..

5 Commits

Author SHA1 Message Date
Konstantin Haase
381b9b2c76 add jobs renderer 2015-05-27 15:19:49 +02:00
Konstantin Haase
b32b5088f5 fix copy pasta 2015-05-27 15:19:41 +02:00
Konstantin Haase
2455cf3c42 add job renderer 2015-05-27 15:17:26 +02:00
Konstantin Haase
be64e36102 Merge branch 'master' into rkh-v3-jobs 2015-05-26 17:12:08 +02:00
Konstantin Haase
ce521f0277 v3: start working on jobs api 2015-05-21 17:49:37 +02:00
584 changed files with 3454 additions and 25511 deletions

View File

@ -1,2 +1,2 @@
https://github.com/heroku/heroku-buildpack-ruby.git
https://github.com/ryandotsmith/nginx-buildpack.git
https://github.com/drogus/last-commit-sha-buildpack.git

12
.gitignore vendored
View File

@ -1,12 +1,8 @@
config/travis.yml
config/database.yml
config/nginx.conf
config/skylight.yml
tmp/
logs/
.yardoc
log/
vendor
config/skylight.yml
.coverage
*.env
.ruby-gemset
tmp

3
.rspec
View File

@ -1,3 +0,0 @@
--require spec_helper
--colour
--tty

View File

@ -1 +1 @@
2.2.3
2.1.5

View File

@ -2,7 +2,7 @@ language: ruby
sudo: false
rvm: 2.2.3
rvm: 2.1.5
env:
global:
@ -18,4 +18,4 @@ services:
- redis
before_script:
- 'RAILS_ENV=test bundle exec rake db:create --trace'
- 'RAILS_ENV=test bundle exec rake db:create db:migrate --trace'

24
Gemfile
View File

@ -1,14 +1,14 @@
source 'https://rubygems.org'
gemspec
ruby '2.1.2' if ENV.key?('DYNO')
gem 's3', github: 'travis-ci/s3'
gem 'travis-core', github: 'travis-ci/travis-core'
gem 'travis-support', github: 'travis-ci/travis-support'
gem 'travis-amqp', github: 'travis-ci/travis-amqp'
gem 'travis-config', '~> 0.1.0'
gem 'travis-settings', github: 'travis-ci/travis-settings'
gem 'travis-sidekiqs', github: 'travis-ci/travis-sidekiqs'
gem 'travis-sidekiqs', github: 'travis-ci/travis-sidekiqs', require: nil
gem 'travis-yaml', github: 'travis-ci/travis-yaml'
gem 'mustermann', github: 'rkh/mustermann'
gem 'sinatra'
@ -16,11 +16,11 @@ gem 'sinatra-contrib', require: nil #github: 'sinatra/sinatra-contrib', require:
gem 'active_model_serializers'
gem 'unicorn'
gem 'sentry-raven'
gem 'sentry-raven', github: 'getsentry/raven-ruby'
gem 'yard-sinatra', github: 'rkh/yard-sinatra'
gem 'rack-contrib'
gem 'rack-contrib', github: 'rack/rack-contrib'
gem 'rack-cache', github: 'rtomayko/rack-cache'
gem 'rack-attack', '5.0.0.beta1'
gem 'rack-attack'
gem 'gh'
gem 'bunny', '~> 0.8.0'
gem 'dalli'
@ -31,22 +31,12 @@ gem 'micro_migrations'
gem 'simplecov'
gem 'skylight', '~> 0.6.0.beta.1'
gem 'stackprof'
gem 'netaddr'
gem 'jemalloc'
gem 'customerio'
group :development, :test do
gem 'travis-migrations', github: 'travis-ci/travis-migrations'
end
group :test do
gem 'rspec', '~> 2.13'
gem 'rspec-its'
gem 'factory_girl', '~> 2.4.0'
gem 'mocha', '~> 0.12'
gem 'database_cleaner', '~> 0.8.0'
gem 'timecop', '~> 0.8.0'
end
group :development do

View File

@ -1,13 +1,28 @@
GIT
remote: git://github.com/eric/metriks-librato_metrics.git
revision: 2c124f024fd2e34378260cd24b0e8687ff9bd196
revision: ccbeb751ec5fc4edfe446d8a67a423b96ebe86c7
specs:
metriks-librato_metrics (1.0.5)
metriks-librato_metrics (1.0.2)
metriks (>= 0.9.9.6)
GIT
remote: git://github.com/getsentry/raven-ruby.git
revision: 84392e5db701f0b5c66802aab9cc82ef9a5ad830
specs:
sentry-raven (0.10.1)
faraday (>= 0.7.6)
uuidtools
GIT
remote: git://github.com/rack/rack-contrib.git
revision: 1b11346d729efd88b274cd7f704e0bca9eb3de7a
specs:
rack-contrib (1.2.0)
rack (>= 0.9.1)
GIT
remote: git://github.com/rkh/mustermann.git
revision: 9611951c5c789ad8227a740ae142c157a8bf7401
revision: fa22e2cf4cfdb57f452c366eac66f241827b7e9c
specs:
mustermann (0.4.0)
tool (~> 0.2)
@ -21,9 +36,9 @@ GIT
GIT
remote: git://github.com/rtomayko/rack-cache.git
revision: 2d6618172c39c53dceab2e2946d87496154f3e52
revision: d00e6e491fcc7bdca9c27d735abde5c4fdb48cd9
specs:
rack-cache (1.6.1)
rack-cache (1.2)
rack (>= 0.4)
GIT
@ -34,42 +49,45 @@ GIT
proxies (~> 0.2.0)
GIT
remote: git://github.com/travis-ci/travis-amqp.git
revision: 3966b3651adfd1c544f53d49d5986ac16cd9c4bc
remote: git://github.com/travis-ci/travis-core.git
revision: 1dbb86846491b05c189e9b7bb842a52e018e8dd3
specs:
travis-amqp (0.0.1)
GIT
remote: git://github.com/travis-ci/travis-migrations.git
revision: dc432e45354287c617c3ae07a72e9e3c4be012cd
specs:
travis-migrations (0.0.2)
GIT
remote: git://github.com/travis-ci/travis-settings.git
revision: d510e63b6c6f059cccae141c265e7a0c7236d1fd
specs:
travis-settings (0.0.1)
activemodel
virtus
travis-core (0.0.1)
actionmailer (~> 3.2.19)
activerecord (~> 3.2.19)
coder (~> 0.4.0)
data_migrations (~> 0.0.1)
gh
hashr (~> 0.0.19)
metriks (~> 0.9.7)
multi_json
pusher (~> 0.14.0)
railties (~> 3.2.19)
rake
redis (~> 3.0)
rollout (~> 1.1.0)
s3 (~> 0.3)
simple_states (~> 1.0.0)
thor (~> 0.14.6)
travis-config (~> 0.1.0)
virtus (~> 1.0.0)
GIT
remote: git://github.com/travis-ci/travis-sidekiqs.git
revision: c5d4a4abc6c3737f9c43d3333efb94daa18b9fbb
revision: 21a2fee158e25252dd78f5fa31e81b4f6583be23
specs:
travis-sidekiqs (0.0.1)
redis-namespace
sidekiq
GIT
remote: git://github.com/travis-ci/travis-support.git
revision: 2cd02d2a06fdd1e2fc2f129148c168b56f7c190f
revision: e7f81093f83bd029cca6508739c5720e57e3d571
specs:
travis-support (0.0.1)
GIT
remote: git://github.com/travis-ci/travis-yaml.git
revision: 032caed23af8ed1ed55e9204bb91316f3ada2f74
revision: 380b9db24a3cefa2b7fa3718ac49bd1db8761bfd
specs:
travis-yaml (0.2.0)
@ -77,36 +95,28 @@ PATH
remote: .
specs:
travis-api (0.0.1)
activerecord (~> 3.2.19)
coder (~> 0.4.0)
composite_primary_keys (~> 5.0)
google-api-client (~> 0.9.4)
hashr
memcachier
multi_json
mustermann (~> 0.4)
pg
pusher (~> 0.14.0)
rack-contrib (~> 1.1)
rack-ssl (~> 1.3, >= 1.3.3)
railties (~> 3.2.19)
redcarpet (~> 2.1)
redis (~> 3.0)
rollout (~> 1.1.0)
simple_states (~> 1.0.0)
sinatra (~> 1.3)
sinatra-contrib (~> 1.3)
tool
travis-core
travis-support
useragent
virtus (~> 1.0.0)
GEM
remote: https://rubygems.org/
specs:
actionpack (3.2.22.2)
activemodel (= 3.2.22.2)
activesupport (= 3.2.22.2)
actionmailer (3.2.21)
actionpack (= 3.2.21)
mail (~> 2.5.4)
actionpack (3.2.21)
activemodel (= 3.2.21)
activesupport (= 3.2.21)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
@ -114,20 +124,20 @@ GEM
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
active_model_serializers (0.9.5)
active_model_serializers (0.9.0)
activemodel (>= 3.2)
activemodel (3.2.22.2)
activesupport (= 3.2.22.2)
activemodel (3.2.21)
activesupport (= 3.2.21)
builder (~> 3.0.0)
activerecord (3.2.22.2)
activemodel (= 3.2.22.2)
activesupport (= 3.2.22.2)
activerecord (3.2.21)
activemodel (= 3.2.21)
activesupport (= 3.2.21)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.22.2)
activesupport (3.2.21)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
addressable (2.4.0)
addressable (2.3.8)
arel (3.0.3)
atomic (1.1.99)
avl_tree (1.1.3)
@ -135,34 +145,38 @@ GEM
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
backports (3.6.8)
backports (3.6.4)
builder (3.0.4)
bunny (0.8.0)
celluloid (0.16.0)
timers (~> 4.0.0)
coder (0.4.0)
coderay (1.1.1)
coderay (1.1.0)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
composite_primary_keys (5.0.14)
activerecord (~> 3.2.0, >= 3.2.9)
concurrent-ruby (1.0.2)
connection_pool (2.2.0)
customerio (1.0.0)
multi_json (~> 1.0)
dalli (2.7.6)
connection_pool (2.1.1)
dalli (2.7.2)
data_migrations (0.0.1)
activerecord
rake
database_cleaner (0.8.0)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
diff-lcs (1.2.5)
docile (1.1.5)
dotenv (0.7.0)
equalizer (0.0.11)
erubis (2.7.0)
factory_girl (2.4.2)
activesupport
faraday (0.9.2)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
ffi (1.9.10)
foreman (0.82.0)
thor (~> 0.19.1)
ffi (1.9.6)
foreman (0.64.0)
dotenv (~> 0.7.0)
thor (>= 0.13.6)
gh (0.14.0)
addressable
backports
@ -170,47 +184,23 @@ GEM
multi_json (~> 1.0)
net-http-persistent (>= 2.7)
net-http-pipeline
git-version-bump (0.15.1)
google-api-client (0.9.8)
addressable (~> 2.3)
googleauth (~> 0.5)
httpclient (~> 2.7)
hurley (~> 0.1)
memoist (~> 0.11)
mime-types (>= 1.6)
representable (~> 2.3.0)
retriable (~> 2.0)
thor (~> 0.19)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
logging (~> 2.0)
memoist (~> 0.12)
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
hashr (0.0.22)
hike (1.2.3)
hitimes (1.2.4)
httpclient (2.8.0)
hurley (0.2)
hitimes (1.2.2)
httpclient (2.6.0.1)
i18n (0.7.0)
ice_nine (0.11.2)
jemalloc (1.0.1)
ice_nine (0.11.1)
journey (1.0.4)
json (1.8.3)
jwt (1.5.4)
kgio (2.10.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
little-plugger (1.1.4)
logging (2.1.0)
little-plugger (~> 1.1)
multi_json (~> 1.10)
json (1.8.2)
kgio (2.9.2)
listen (1.0.3)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
rb-kqueue (>= 0.2)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
memcachier (0.0.2)
memoist (0.14.0)
metaclass (0.0.4)
method_source (0.8.2)
metriks (0.9.9.6)
@ -223,58 +213,52 @@ GEM
mime-types (1.25.1)
mocha (0.14.0)
metaclass (~> 0.0.1)
multi_json (1.12.1)
multi_json (1.11.0)
multipart-post (2.0.0)
net-http-persistent (2.9.4)
net-http-pipeline (1.0.1)
netaddr (1.5.1)
os (0.9.6)
pg (0.18.4)
pg (0.18.2)
polyglot (0.3.5)
proxies (0.2.1)
pry (0.10.3)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pusher (0.14.6)
pusher (0.14.4)
httpclient (~> 2.5)
multi_json (~> 1.0)
pusher-signature (~> 0.1.8)
pusher-signature (0.1.8)
rack (1.4.7)
rack-attack (5.0.0.beta1)
signature (~> 0.1.8)
rack (1.4.5)
rack-attack (4.2.0)
rack
rack-contrib (1.4.0)
git-version-bump (~> 0.15)
rack (~> 1.4)
rack-protection (1.5.3)
rack
rack-ssl (1.3.4)
rack
rack-test (0.6.3)
rack (>= 1.0)
railties (3.2.22.2)
actionpack (= 3.2.22.2)
activesupport (= 3.2.22.2)
railties (3.2.21)
actionpack (= 3.2.21)
activesupport (= 3.2.21)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.16.0)
raindrops (0.13.0)
rake (0.9.6)
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rb-kqueue (0.2.3)
ffi (>= 0.5.0)
rdoc (3.12.2)
json (~> 1.4)
redcarpet (2.3.0)
redis (3.3.0)
redis-namespace (1.5.2)
redis (3.2.1)
redis-namespace (1.5.1)
redis (~> 3.0, >= 3.0.4)
representable (2.3.0)
uber (~> 0.0.7)
rerun (0.11.0)
listen (~> 3.0)
retriable (2.1.0)
rerun (0.8.2)
listen (~> 1.0.3)
rollout (1.1.0)
rspec (2.99.0)
rspec-core (~> 2.99.0)
@ -283,42 +267,34 @@ GEM
rspec-core (2.99.2)
rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0)
rspec-its (1.0.1)
rspec-core (>= 2.99.0.beta1)
rspec-expectations (>= 2.99.0.beta1)
rspec-mocks (2.99.4)
ruby_dep (1.3.1)
sentry-raven (1.0.0)
faraday (>= 0.7.6)
sidekiq (4.1.2)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
redis (~> 3.2, >= 3.2.1)
signet (0.7.2)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (~> 1.5)
multi_json (~> 1.10)
rspec-mocks (2.99.2)
sidekiq (3.3.0)
celluloid (>= 0.16.0)
connection_pool (>= 2.0.0)
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
signature (0.1.8)
simple_states (1.0.1)
activesupport
hashr (~> 0.0.10)
simplecov (0.11.2)
simplecov (0.9.1)
docile (~> 1.1.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
sinatra (1.4.6)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
sinatra-contrib (1.4.7)
sinatra-contrib (1.4.2)
backports (>= 2.0)
multi_json
rack-protection
rack-test
sinatra (~> 1.4.0)
tilt (>= 1.3, < 3)
skylight (0.6.2.beta.2)
tilt (~> 1.3)
skylight (0.6.0.beta.1)
activesupport (>= 3.0.0)
slop (3.6.0)
sprockets (2.2.3)
@ -326,20 +302,25 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
stackprof (0.2.9)
thor (0.19.1)
stackprof (0.2.7)
thor (0.14.6)
thread_safe (0.3.5)
tilt (1.4.1)
timecop (0.8.1)
timers (4.0.1)
hitimes
tool (0.2.3)
travis-config (0.1.4)
travis-config (0.1.0)
hashr (~> 0.0)
tzinfo (0.3.49)
uber (0.0.15)
unicorn (5.1.0)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.44)
unicorn (4.8.3)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
useragent (0.16.7)
useragent (0.13.3)
uuidtools (2.1.5)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
@ -353,46 +334,36 @@ PLATFORMS
DEPENDENCIES
active_model_serializers
bunny (~> 0.8.0)
customerio
dalli
database_cleaner (~> 0.8.0)
factory_girl (~> 2.4.0)
foreman
gh
jemalloc
metriks (= 0.9.9.6)
metriks-librato_metrics!
micro_migrations
mocha (~> 0.12)
mustermann!
netaddr
pry
rack-attack (= 5.0.0.beta1)
rack-attack
rack-cache!
rack-contrib
rack-contrib!
rake (~> 0.9.2)
rb-fsevent (~> 0.9.1)
rerun
rspec (~> 2.13)
rspec-its
s3!
sentry-raven
sentry-raven!
simplecov
sinatra
sinatra-contrib
skylight (~> 0.6.0.beta.1)
stackprof
timecop (~> 0.8.0)
travis-amqp!
travis-api!
travis-config (~> 0.1.0)
travis-migrations!
travis-settings!
travis-core!
travis-sidekiqs!
travis-support!
travis-yaml!
unicorn
yard-sinatra!
BUNDLED WITH
1.12.5

21
LICENSE
View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Travis CI GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,4 +1,3 @@
web: ./script/server
console: bundle exec je ./script/console
sidekiq: bundle exec je sidekiq -c 4 -r ./lib/travis/sidekiq.rb -q build_cancellations, -q build_restarts, -q job_cancellations, -q job_restarts
start_crons: ./script/start_crons
web: bundle exec ./script/server
console: bundle exec ./script/console
sidekiq: bundle exec sidekiq -c 4 -r ./lib/travis/sidekiq.rb -q build_cancellations, -q build_restarts, -q job_cancellations, -q job_restarts

102
README.md
View File

@ -4,68 +4,47 @@ This is the app running on https://api.travis-ci.org/
## Requirements
You will need the following packages to get travis-api to work:
1. PostgreSQL 9.3 or higher
2. Bundler
3. Redis Server
4. *Optional:* RabbitMQ Server
5. Nginx -
*If working in Ubuntu please install nginx manually from source: Download and extract latest nginx version, open a terminal in extracted folder and then run the following:*
```sh-session
$ sudo apt-get install libpcre3 libpcre3-dev
$ auto/configure --user=$USER
$ make
$ sudo make install
$ sudo ln -s /usr/local/nginx/sbin/nginx /bin/nginx
```
1. Redis
1. RabbitMQ
## Installation
### Setup
```sh-session
$ bundle install
```
$ bundle install
### Database setup
*You might need to create a role first. For this you should run the following:*
1. `rake db:create db:structure:load`
1. Clone `travis-logs` and copy the `logs` database (assume the PostgreSQL user is `postgres`):
```sh-session
$ sudo -u postgres psql -c "CREATE USER yourusername WITH SUPERUSER PASSWORD 'yourpassword'"
cd ..
git clone https://github.com/travis-ci/travis-logs.git
cd travis-logs
rvm jruby do bundle exec rake db:migrate # `travis-logs` requires JRuby
psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_development
pg_dump -t logs travis_logs_development | psql -U postgres travis_development
```
NB detail for how `rake` sets up the database can be found in the `Rakefile`. In the `namespace :db` block you will see the database name is configured using the environment variable RAILS_ENV. If you are using a different configuration you will have to make your own adjustments.
Repeat the database steps for `RAILS_ENV=test`.
```sh-session
$ RAILS_ENV=development bundle exec rake db:create
$ RAILS_ENV=test bundle exec rake db:create
```
#### Optional
Clone `travis-logs` and copy the `logs` database (assume the PostgreSQL user is `postgres`):
```sh-session
$ cd ..
$ git clone https://github.com/travis-ci/travis-logs.git
$ cd travis-logs
$ rvm jruby do bundle exec rake db:migrate # `travis-logs` requires JRuby
$ psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_development
$ pg_dump -t logs travis_logs_development | psql -U postgres travis_development
$ RAILS_ENV=test bundle exec rake db:create
$ pushd ../travis-logs
$ RAILS_ENV=test rvm jruby do bundle exec rake db:migrate
$ psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_test
$ pg_dump -t logs travis_logs_test | psql -U postgres travis_test
$ popd
RAILS_ENV=test rake db:create db:structure:load
pushd ../travis-logs
RAILS_ENV=test rvm jruby do bundle exec rake db:migrate
psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_test
pg_dump -t logs travis_logs_test | psql -U postgres travis_test
popd
```
### Run tests
```sh-session
$ bundle exec rake
```
$ rake spec
### Run the server
```sh-session
$ bundle exec script/server
```
If you have problems with Nginx because the websocket is already in use, try restarting your computer.
$ script/server
## Contributing
@ -77,4 +56,33 @@ If you have problems with Nginx because the websocket is already in use, try res
### API documentation
v3 documentation can be found at https://developer.travis-ci.org which is a repository that can be found at https://github.com/travis-pro/developer
We use source code comments to add documentation. If the server is running, you
can browse an HTML documenation at [`/docs`](http://localhost:5000/docs).
### Project architecture
lib
`-- travis
`-- api
`-- app
|-- endpoint # API endpoints
|-- extensions # Sinatra extensions
|-- helpers # Sinatra helpers
`-- middleware # Rack middleware
Classes inheriting from `Endpoint` or `Middleware`, they will automatically be
set up properly.
Each endpoint class gets mapped to a prefix, which defaults to the snake-case
class name (i.e. `Travis::Api::App::Profile` will map to `/profile`).
It can be overridden by setting `:prefix`:
``` ruby
require 'travis/api/app'
class Travis::Api::App
class MyRouts < Endpoint
set :prefix, '/awesome'
end
end
```

149
Rakefile
View File

@ -1,34 +1,127 @@
namespace :db do
env = ENV["RAILS_ENV"]
if env != 'production'
desc "Create and migrate the #{env} database"
task :create do
sh "createdb travis_#{env}" rescue nil
sh "psql -q travis_#{env} < #{Gem.loaded_specs['travis-migrations'].full_gem_path}/db/structure.sql"
end
end
require 'bundler/setup'
require 'travis'
require 'travis/engine'
begin
ENV['SCHEMA'] = File.expand_path('../db/schema.rb', $:.detect { |p| p.include?('travis-core') })
require 'micro_migrations'
rescue LoadError
# we can't load micro migrations on production
end
require 'travis'
begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new
task default: :spec
rescue LoadError
warn "could not load rspec"
end
# begin
# require 'rspec'
# require 'rspec/core/rake_task'
# RSpec::Core::RakeTask.new(:spec)
#
# RSpec::Core::RakeTask.new(:spec_core) do |t|
# t.pattern = 'spec_core/**{,/*/**}/*_spec.rb'
# end
#
# task :default => [:spec]
# rescue LoadError => e
# puts e.inspect
# end
desc "generate gemspec"
task 'travis-api.gemspec' do
content = File.read 'travis-api.gemspec'
# not sure how else to include the spec_helper
namespace :spec do
desc 'Run all specs'
task :all do
sh 'bundle exec rspec -r spec_helper spec'
fields = {
authors: `git shortlog -sn`.scan(/[^\d\s].*/),
email: `git shortlog -sne`.scan(/[^<]+@[^>]+/),
files: `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ }
}
fields.each do |field, values|
updated = " s.#{field} = ["
updated << values.map { |v| "\n %p" % v }.join(',')
updated << "\n ]"
content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated)
end
File.open('travis-api.gemspec', 'w') { |f| f << content }
end
task :default => :'spec:all'
task default: 'travis-api.gemspec'
tasks_path = File.expand_path('../lib/tasks/*.rake', __FILE__)
Dir.glob(tasks_path).each { |r| import r }
module ActiveRecord
class Migration
class << self
attr_accessor :disable_ddl_transaction
end
# Disable DDL transactions for this migration.
def self.disable_ddl_transaction!
@disable_ddl_transaction = true
end
def disable_ddl_transaction # :nodoc:
self.class.disable_ddl_transaction
end
end
class Migrator
def use_transaction?(migration)
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
end
def ddl_transaction(migration, &block)
if use_transaction?(migration)
Base.transaction { block.call }
else
block.call
end
end
def migrate(&block)
current = migrations.detect { |m| m.version == current_version }
target = migrations.detect { |m| m.version == @target_version }
if target.nil? && @target_version && @target_version > 0
raise UnknownMigrationVersionError.new(@target_version)
end
start = up? ? 0 : (migrations.index(current) || 0)
finish = migrations.index(target) || migrations.size - 1
runnable = migrations[start..finish]
# skip the last migration if we're headed down, but not ALL the way down
runnable.pop if down? && target
ran = []
runnable.each do |migration|
if block && !block.call(migration)
next
end
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
seen = migrated.include?(migration.version.to_i)
# On our way up, we skip migrating the ones we've already migrated
next if up? && seen
# On our way down, we skip reverting the ones we've never migrated
if down? && !seen
migration.announce 'never migrated, skipping'; migration.write
next
end
begin
ddl_transaction(migration) do
migration.migrate(@direction)
record_version_state_after_migrating(migration.version)
end
ran << migration
rescue => e
canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
end
end
ran
end
end
class MigrationProxy
delegate :disable_ddl_transaction, to: :migration
end
end

View File

@ -1,82 +1,3 @@
#!/usr/bin/env bash
#!/bin/sh
# make sure we kill all child processes once done
trap '{ pkill -P $$; rm -f config/nginx.conf; exit 255; }' EXIT
if [ -f bin/nginx ]; then
nginx=bin/nginx
else
which nginx &>/dev/null || { echo "nginx not found" && exit 1; }
nginx=nginx
fi
psmgr=$tmp_dir/nginx-buildpack-wait
rm -f $psmgr
mkfifo $psmgr
#Evaluate config to get $PORT
erb config/nginx.conf.erb > config/nginx.conf
n=1
while getopts :f option ${@:1:2}
do
case "${option}"
in
f) FORCE=$OPTIND; n=$((n+1));;
esac
done
#Initialize log directory.
mkdir -p logs/nginx
touch logs/nginx/access.log logs/nginx/error.log
echo 'buildpack=nginx at=logs-initialized'
#Start log redirection.
(
#Redirect NGINX logs to stdout.
tail -qF -n 0 logs/nginx/*.log
echo 'logs' >$psmgr
) &
#Start App Server
(
#Take the command passed to this bin and start it.
#E.g. bin/start-nginx bundle exec unicorn -c config/unicorn.rb
COMMAND=${@:$n}
echo "buildpack=nginx at=start-app cmd=$COMMAND"
$COMMAND
echo 'app' >$psmgr
) &
if [[ -z "$FORCE" ]]
then
FILE="$tmp_dir/app-initialized"
#We block on app-initialized so that when NGINX binds to $PORT
#are app is ready for traffic.
while [[ ! -f "$FILE" ]]
do
echo 'buildpack=nginx at=app-initialization'
sleep 1
done
echo 'buildpack=nginx at=app-initialized'
fi
#Start NGINX
(
#We expect nginx to run in foreground.
#We also expect a socket to be at $tmp_dir/nginx.socket.
echo 'buildpack=nginx at=nginx-start'
$nginx -p . -c config/nginx.conf
echo 'nginx' >$psmgr
) &
#This read will block the process waiting on a msg to be put into the fifo.
#If any of the processes defined above should exit,
#a msg will be put into the fifo causing the read operation
#to un-block. The process putting the msg into the fifo
#will use it's process name as a msg so that we can print the offending
#process to stdout.
read exit_process <$psmgr
echo "buildpack=nginx at=exit process=$exit_process"
exit 1
"$@"

View File

@ -20,3 +20,4 @@ development:
test:
<<: *defaults
database: travis_test

View File

@ -1,76 +0,0 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
text/cache-manifest manifest appcache;
image/gif gif;
image/jpeg jpeg jpg;
application/x-javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@ -1,45 +0,0 @@
daemon off;
#Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || ENV['WEB_CONCURRENCY'] || 4 %>;
events {
<% if `uname` != "Darwin\n" %>use epoll;<% end %>
accept_mutex on;
worker_connections 1024;
}
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
server_tokens off;
log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
access_log logs/nginx/access.log l2met;
error_log logs/nginx/error.log;
include mime.types;
default_type application/octet-stream;
sendfile on;
#Must read the body in 5 seconds.
client_body_timeout 5;
upstream app_server {
server unix:<%= ENV["tmp_dir"] %>/nginx.socket fail_timeout=0;
}
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
}

View File

@ -2,8 +2,8 @@ root = File.expand_path('../..', __FILE__)
rackup "#{root}/config.ru"
tmp_dir = ENV.fetch("tmp_dir", "/tmp")
bind "unix://#{tmp_dir}/nginx.socket"
bind 'unix:///tmp/nginx.socket'
environment ENV['RACK_ENV'] || 'development'
threads 0, 16

View File

@ -1,7 +0,0 @@
#!/bin/bash
export RUBY_HEAP_MIN_SLOTS=800000
export RUBY_GC_HEAP_INIT_SLOTS=$RUBY_HEAP_MIN_SLOTS
export RUBY_GC_MALLOC_LIMIT=59000000
export RUBY_HEAP_SLOTS_INCREMENT=10000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_HEAP_FREE_MIN=100000

View File

@ -1,16 +1,19 @@
# http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/
worker_processes Integer(ENV.fetch('WEB_CONCURRENCY')) # amount of unicorn workers to spin up
timeout 30 # restarts workers that hang for 30 seconds
worker_processes 4 # amount of unicorn workers to spin up
timeout 30 # restarts workers that hang for 15 seconds
tmp_dir = ENV.fetch("tmp_dir", "/tmp")
listen File.expand_path("nginx.socket", tmp_dir), backlog: 1024
listen '/tmp/nginx.socket', backlog: 1024
require 'fileutils'
before_fork do |server, worker|
# preload travis so we can have copy on write
require 'travis/api/app'
# signal to nginx we're ready
FileUtils.touch("#{tmp_dir}/app-initialized")
before_fork do |server,worker|
FileUtils.touch('/tmp/app-initialized')
end
before_exec do |server|
ENV['RUBY_HEAP_MIN_SLOTS']=800000
ENV['RUBY_GC_MALLOC_LIMIT']=59000000
ENV['RUBY_HEAP_SLOTS_INCREMENT']=10000
ENV['RUBY_HEAP_SLOTS_GROWTH_FACTOR']=1
ENV['RUBY_HEAP_FREE_MIN']=100000
end

Binary file not shown.

View File

@ -1,67 +0,0 @@
require 'pusher'
require 'travis/support'
require 'travis/support/database'
require 'travis/redis_pool'
require 'travis/errors'
module Travis
class << self
def services=(services)
@services = services
end
def services
@services ||= Travis::Services
end
end
require 'travis/model'
require 'travis/task'
require 'travis/event'
require 'travis/api/serialize'
require 'travis/config/defaults'
require 'travis/features'
require 'travis/github'
require 'travis/notification'
require 'travis/services'
class UnknownRepository < StandardError; end
class GithubApiError < StandardError; end
class AdminMissing < StandardError; end
class RepositoryMissing < StandardError; end
class LogAlreadyRemoved < StandardError; end
class AuthorizationDenied < StandardError; end
class JobUnfinished < StandardError; end
class << self
def setup(options = {})
@config = Config.load(*options[:configs])
@redis = Travis::RedisPool.new(config.redis.to_h)
Travis.logger.info('Setting up Travis::Core')
Github.setup
Services.register
Github::Services.register
end
attr_accessor :redis, :config
def pusher
@pusher ||= ::Pusher.tap do |pusher|
pusher.app_id = config.pusher.app_id
pusher.key = config.pusher.key
pusher.secret = config.pusher.secret
pusher.scheme = config.pusher.scheme if config.pusher.scheme
pusher.host = config.pusher.host if config.pusher.host
pusher.port = config.pusher.port if config.pusher.port
end
end
def states_cache
@states_cache ||= Travis::StatesCache.new
end
end
setup
end

View File

@ -4,37 +4,27 @@ require 'active_record_postgres_variables'
# now actually load travis
require 'travis'
require 'travis/amqp'
require 'travis/model'
require 'travis/support/amqp'
require 'travis/states_cache'
require 'rack'
require 'rack/protection'
require 'rack/contrib/config'
require 'rack/contrib/jsonp'
require 'rack/contrib/post_body_content_type_parser'
require 'rack/contrib'
require 'dalli'
require 'memcachier'
require 'rack/cache'
require 'travis/api/attack'
require 'rack/attack'
require 'active_record'
require 'redis'
require 'gh'
require 'raven'
require 'raven/integrations/rack'
require 'sidekiq'
require 'metriks/reporter/logger'
require 'metriks/librato_metrics_reporter'
require 'travis/support/log_subscriber/active_record_metrics'
require 'fileutils'
require 'securerandom'
module Travis::Api
end
require 'travis/api/app/endpoint'
require 'travis/api/app/middleware'
require 'travis/api/instruments'
require 'travis/api/serialize/v2'
require 'travis/api/v2/http'
require 'travis/api/v3'
require 'travis/api/app/stack_instrumentation'
require 'travis/api/app/error_handling'
@ -82,27 +72,42 @@ module Travis::Api
end
def self.deploy_sha
@deploy_sha ||= ENV['HEROKU_SLUG_COMMIT'] || SecureRandom.hex(5)
@deploy_sha ||= File.exist?(deploy_sha_path) ? File.read(deploy_sha_path)[0..7] : 'deploy-sha'
end
def self.deploy_sha_path
File.expand_path('../../../../.deploy-sha', __FILE__)
end
attr_accessor :app
def initialize
@app = Rack::Builder.app do
# if stackprof = ENV['STACKPROF']
# require 'stackprof'
# modes = ['wall', 'cpu', 'object', 'custom']
# mode = modes.include?(stackprof) ? stackprof.to_sym : :cpu
# Travis.logger.info "Setting up profiler: #{mode}"
# use StackProf::Middleware, enabled: true, save_every: 1, mode: mode
# end
if stackprof = ENV['STACKPROF']
require 'stackprof'
modes = ['wall', 'cpu', 'object', 'custom']
mode = modes.include?(stackprof) ? stackprof.to_sym : :cpu
Travis.logger.info "Setting up profiler: #{mode}"
use StackProf::Middleware, enabled: true, save_every: 1, mode: mode
end
extend StackInstrumentation
use Travis::Api::App::Middleware::Skylight
use(Rack::Config) { |env| env['metriks.request.start'] ||= Time.now.utc }
Rack::Utils::HTTP_STATUS_CODES[420] = "Enhance Your Calm"
use Rack::Attack
Rack::Attack.blacklist('block client requesting ruby builds') do |req|
req.ip == "130.15.4.210"
end
Rack::Attack.blacklisted_response = lambda do |env|
[ 420, {}, ['Enhance Your Calm']]
end
use Travis::Api::App::Cors # if Travis.env == 'development' ???
use Raven::Rack if Travis::Api::App.use_monitoring?
use Raven::Rack if Travis.env == 'production' || Travis.env == 'staging'
use Rack::SSL if Endpoint.production?
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
@ -127,9 +132,7 @@ module Travis::Api
use Travis::Api::App::Middleware::Logging
use Travis::Api::App::Middleware::ScopeCheck
use Travis::Api::App::Middleware::UserAgentTracker
# make sure this is below ScopeCheck so we have the token
use Rack::Attack if Endpoint.production? and not Travis.config.enterprise
use Travis::Api::App::Middleware::Metriks
# if this is a v3 API request, ignore everything after
use Travis::API::V3::OptIn
@ -137,9 +140,6 @@ module Travis::Api
# rewrite should come after V3 hook
use Travis::Api::App::Middleware::Rewrite
# v3 has its own metriks
use Travis::Api::App::Middleware::Metriks
SettingsEndpoint.subclass :env_vars
if Travis.config.endpoints.ssh_key
SingletonSettingsEndpoint.subclass :ssh_key
@ -176,13 +176,14 @@ module Travis::Api
def self.setup!
setup_travis
load_endpoints
setup_endpoints
@setup = true
end
def self.setup_travis
Travis::Async.enabled = true
Travis::Amqp.setup(Travis.config.amqp)
Travis::Amqp.config = Travis.config.amqp
setup_database_connections
@ -192,7 +193,7 @@ module Travis::Api
end
end
if use_monitoring? && !console?
if use_monitoring? and not console?
setup_monitoring
end
end
@ -203,10 +204,8 @@ module Travis::Api
Travis::Database.connect
if Travis.config.logs_database
pool_size = ENV['DATABASE_POOL_SIZE']
Travis.config.logs_database[:pool] = pool_size.to_i if pool_size
Travis::LogsModel.establish_connection 'logs_database'
Log.establish_connection 'logs_database'
Log::Part.establish_connection 'logs_database'
end
end
@ -218,6 +217,11 @@ module Travis::Api
Travis::Metrics.setup
end
def self.load_endpoints
Dir.glob("#{__dir__}/app/middleware/*.rb").each { |f| require f[%r[(?<=lib/).+(?=\.rb$)]] }
Dir.glob("#{__dir__}/app/endpoint/*.rb").each { |f| require f[%r[(?<=lib/).+(?=\.rb$)]] }
end
def self.setup_endpoints
Base.subclasses.each(&:setup)
end

View File

@ -1,8 +1,6 @@
require 'travis/api/app'
require 'sinatra/base'
require 'mustermann'
require 'travis/api/app'
require 'travis/api/app/extensions'
require 'travis/api/app/helpers'
class Travis::Api::App
# Superclass for any endpoint and middleware.

View File

@ -15,11 +15,6 @@ class Travis::Api::App
options // do
headers['Access-Control-Allow-Methods'] = "HEAD, GET, POST, PATCH, PUT, DELETE"
headers['Access-Control-Allow-Headers'] = "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since, X-User-Agent, Travis-API-Version"
# cache OPTIONS for 24 hours to avoid excessive preflight requests and speed up access
# browsers might still limit this value to 10 minutes, see caveats
# http://stackoverflow.com/a/12021982
headers['Access-Control-Max-Age'] = "86400"
end
end
end

View File

@ -1,7 +1,6 @@
require 'travis/api/app'
require 'addressable/uri'
require 'active_record/base'
require 'travis/api/app'
require 'travis/api/app/base'
class Travis::Api::App
# Superclass for HTTP endpoints. Takes care of prefixing.
@ -49,23 +48,3 @@ class Travis::Api::App
end
end
end
require 'travis/api/app/endpoint/accounts'
require 'travis/api/app/endpoint/authorization'
require 'travis/api/app/endpoint/branches'
require 'travis/api/app/endpoint/broadcasts'
require 'travis/api/app/endpoint/builds'
require 'travis/api/app/endpoint/documentation'
require 'travis/api/app/endpoint/endpoints'
require 'travis/api/app/endpoint/env_vars'
require 'travis/api/app/endpoint/home'
require 'travis/api/app/endpoint/hooks'
require 'travis/api/app/endpoint/jobs'
require 'travis/api/app/endpoint/lint'
require 'travis/api/app/endpoint/logs'
require 'travis/api/app/endpoint/repos'
require 'travis/api/app/endpoint/requests'
require 'travis/api/app/endpoint/setting_endpoint'
require 'travis/api/app/endpoint/singleton_settings_endpoint'
require 'travis/api/app/endpoint/uptime'
require 'travis/api/app/endpoint/users'

View File

@ -1,10 +1,7 @@
require 'travis/api/app'
require 'addressable/uri'
require 'faraday'
require 'securerandom'
require 'customerio'
require 'travis/api/app'
require 'travis/github/education'
require 'travis/github/oauth'
class Travis::Api::App
class Endpoint
@ -81,7 +78,6 @@ class Travis::Api::App
#
# * **github_token**: GitHub token for checking authorization (required)
post '/github' do
check_agent
unless params[:github_token]
halt 422, { "error" => "Must pass 'github_token' parameter" }
end
@ -98,7 +94,6 @@ class Travis::Api::App
# * **redirect_uri**: URI to redirect to after handshake.
get '/handshake' do
handshake do |user, token, redirect_uri|
if target_ok? redirect_uri
content_type :html
data = { user: user, token: token, uri: redirect_uri }
@ -114,7 +109,7 @@ class Travis::Api::App
# access token and user payload to the parent window via postMessage.
#
# However, the endpoint to send the payload to has to be explicitely
# safelisted in production, as this is endpoint is only meant to be used
# whitelisted in production, as this is endpoint is only meant to be used
# with the official Travis CI client at the moment.
#
# Example usage:
@ -150,46 +145,8 @@ class Travis::Api::App
private
def allowed_agents
@allowed_agents ||= redis.smembers('auth_agents')
end
def check_agent
return if settings.test? or allowed_agents.empty?
return if allowed_agents.any? { |a| request.user_agent.to_s.start_with? a }
halt 403, "you are currently not allowed to perform this request. please contact support@travis-ci.com."
end
# update first login date if not set
def update_first_login(user)
unless user.first_logged_in_at
user.update_attributes(first_logged_in_at: Time.now)
end
end
def update_customerio(user)
return unless Travis.config.customerio.site_id
# send event to customer.io
payload = {
:id => user.id,
:name => user.name,
:login => user.login,
:email => primary_email_for_user(user.github_oauth_token),
:created_at => user.created_at.to_i,
:github_id => user.github_id,
:education => user.education,
:first_logged_in_at => user.first_logged_in_at.to_i,
:travis_domain => Travis.config.client_domain
}
customerio.identify(payload)
rescue StandardError => e
Travis.logger.error "Could not update Customer.io for User: #{user.id}:#{user.login} with message:#{e.message}"
end
def serialize_user(user)
rendered = Travis::Api::Serialize.data(user, version: :v2)
rendered = Travis::Api.data(user, version: :v2)
rendered['user'].merge('token' => user.tokens.first.try(:token).to_s)
end
@ -217,8 +174,6 @@ class Travis::Api::App
user = user_for_github_token(github_token)
token = generate_token(user: user, app_id: 0)
payload = params[:state].split(":::", 2)[1]
update_first_login(user)
update_customerio(user)
yield serialize_user(user), token, payload
else
values[:state] = create_state
@ -228,7 +183,6 @@ class Travis::Api::App
end
end
def create_state
state = SecureRandom.urlsafe_base64(16)
redis.sadd('github:states', state)
@ -258,7 +212,6 @@ class Travis::Api::App
super
@user = ::User.find_by_github_id(data['id'])
end
def info(attributes = {})
@ -290,11 +243,8 @@ class Travis::Api::App
user.update_attributes info
else
self.user = ::User.create! info
Travis.run_service(:sync_user, user)
end
Travis::Github::Oauth.update_scopes(user) # unless Travis.env == 'test'
nullify_logins(user.github_id, user.login)
end
@ -346,7 +296,7 @@ class Travis::Api::App
end
def acceptable?(scopes, lossy = false)
Travis::Github::Oauth.wanted_scopes.all? do |scope|
User::Oauth.wanted_scopes.all? do |scope|
acceptable_scopes_for(scope, lossy).any? { |s| scopes.include? s }
end
end
@ -392,15 +342,6 @@ class Travis::Api::App
def allowed_https_targets
@allowed_https_targets ||= Travis.config.auth.target_origin.to_s.split(',')
end
def primary_email_for_user(oauth_token)
# check for the users primary email address (we don't store this info)
GH.with(token: oauth_token, client_id: nil) { GH['user/emails'] }.select { |e| e['primary'] }.first['email']
end
def customerio
Customerio::Client.new(Travis.config.customerio.site_id, Travis.config.customerio.api_key, :json => true)
end
end
end
end
@ -409,7 +350,7 @@ __END__
@@ invalid_target
<script>
console.log('refusing to send a token to <%= target_origin.inspect %>, not safelisted!');
console.log('refusing to send a token to <%= target_origin.inspect %>, not whitelisted!');
</script>
@@ common

View File

@ -1,8 +1,6 @@
require 'travis/api/app'
require 'travis/api/workers/build_cancellation'
require 'travis/api/workers/build_restart'
require 'travis/api/enqueue/services/restart_model'
require 'travis/api/enqueue/services/cancel_model'
class Travis::Api::App
class Endpoint
@ -22,8 +20,7 @@ class Travis::Api::App
post '/:id/cancel' do
Metriks.meter("api.request.cancel_build").mark
service = Travis::Enqueue::Services::CancelModel.new(current_user, { build_id: params[:id] })
service = self.service(:cancel_build, params.merge(source: 'api'))
if !service.authorized?
json = { error: {
message: "You don't have access to cancel build(#{params[:id]})"
@ -42,9 +39,7 @@ class Travis::Api::App
status 422
respond_with json
else
payload = { id: params[:id], user_id: current_user.id, source: 'api' }
service.push("build:cancel", payload)
Travis::Sidekiq::BuildCancellation.perform_async(id: params[:id], user_id: current_user.id, source: 'api')
Metriks.meter("api.request.cancel_build.success").mark
status 204
@ -53,18 +48,16 @@ class Travis::Api::App
post '/:id/restart' do
Metriks.meter("api.request.restart_build").mark
service = Travis::Enqueue::Services::RestartModel.new(current_user, build_id: params[:id])
result = if !service.accept?
service = self.service(:reset_model, build_id: params[:id])
if !service.accept?
status 400
false
result = false
else
payload = { id: params[:id], user_id: current_user.id }
service.push("build:restart", payload)
Travis::Sidekiq::BuildRestart.perform_async(id: params[:id], user_id: current_user.id)
status 202
true
result = true
end
respond_with(result: result, flash: service.messages)
end
end

View File

@ -11,7 +11,7 @@ class Travis::Api::App
host: host,
shorten_host: Travis.config.shorten_host,
assets: Travis.config.assets,
pusher: (Travis.config.pusher_ws || Travis.config.pusher || {}).to_hash.slice(:scheme, :host, :port, :path, :key, :secure, :private),
pusher: (Travis.config.pusher_ws || Travis.config.pusher || {}).to_hash.slice(:scheme, :host, :port, :path, :key),
github: { api_url: GH.current.api_host.to_s, scopes: Travis.config.oauth2.try(:scope).to_s.split(?,) }
# Landing point. Redirects web browsers to [API documentation](#/docs/).
@ -49,18 +49,6 @@ class Travis::Api::App
get '/config' do
{ config: settings.client_config }
end
deploy_sha = File.read(".deploy-sha") if File.exist?(".deploy-sha")
sys_info = {
web_concurrency: ENV['WEB_CONCURRENCY'],
ulimit: `echo "ulimit -u" | bash`.to_i,
dyno: ENV['DYNO'],
deploy_sha: deploy_sha
}
get '/sysinfo' do
sys_info
end
end
end
end

View File

@ -1,8 +1,6 @@
require 'travis/api/app'
require 'travis/api/workers/job_cancellation'
require 'travis/api/workers/job_restart'
require 'travis/api/enqueue/services/restart_model'
require 'travis/api/enqueue/services/cancel_model'
class Travis::Api::App
class Endpoint
@ -29,8 +27,7 @@ class Travis::Api::App
post '/:id/cancel' do
Metriks.meter("api.request.cancel_job").mark
service = Travis::Enqueue::Services::CancelModel.new(current_user, { job_id: params[:id] })
service = self.service(:cancel_job, params.merge(source: 'api'))
if !service.authorized?
json = { error: {
message: "You don't have access to cancel job(#{params[:id]})"
@ -49,8 +46,7 @@ class Travis::Api::App
status 422
respond_with json
else
payload = { id: params[:id], user_id: current_user.id, source: 'api' }
service.push("job:cancel", payload)
Travis::Sidekiq::JobCancellation.perform_async(id: params[:id], user_id: current_user.id, source: 'api')
Metriks.meter("api.request.cancel_job.success").mark
status 204
@ -60,18 +56,15 @@ class Travis::Api::App
post '/:id/restart' do
Metriks.meter("api.request.restart_job").mark
service = Travis::Enqueue::Services::RestartModel.new(current_user, { job_id: params[:id] })
result = if !service.accept?
service = self.service(:reset_model, job_id: params[:id])
if !service.accept?
status 400
false
result = false
else
payload = {id: params[:id], user_id: current_user.id}
service.push("job:restart", payload)
Travis::Sidekiq::JobRestart.perform_async(id: params[:id], user_id: current_user.id)
status 202
true
result = true
end
respond_with(result: result, flash: service.messages)
end

View File

@ -1,6 +1,5 @@
require 'travis/api/app'
require 'travis/api/app/services/schedule_request'
require 'travis/api/enqueue/services/restart_model'
class Travis::Api::App
class Endpoint
@ -20,25 +19,14 @@ class Travis::Api::App
post '/', scope: :private do
if params[:request] && params[:request][:repository]
status 404
respond_with service(:schedule_request, params[:request])
else
# DEPRECATED: this will be removed by 1st of December
#
# TODO It seems this endpoint is still in use, quite a bit:
# https://metrics.librato.com/s/metrics/api.request.restart?duration=2419200&q=api.request.restart
#
# I think we need to properly deprecate this by publishing a blog post.
Metriks.meter("api.request.restart").mark
service = Travis::Enqueue::Services::RestartModel.new(current_user, params)
params[:user_id] = service.target.repository.owner.id
type = params[:build_id] ? 'build' : 'job'
params[:id] = params[:build_id] || params[:job_id]
service.push("#{type}:restart", params)
respond_with(result: true, flash: service.messages)
respond_with service(:reset_model, params)
end
end
end
end
end

View File

@ -9,7 +9,7 @@ class Travis::Api::App
Thread.new do
loop do
begin
Raven.send_event queue.pop
Raven.send queue.pop
rescue Exception => e
puts e.message, e.backtrace
end

View File

@ -1,4 +1,8 @@
require 'travis/api/app/extensions/expose_pattern'
require 'travis/api/app/extensions/scoping'
require 'travis/api/app/extensions/smart_constants'
require 'travis/api/app/extensions/subclass_tracker'
require 'travis/api/app'
class Travis::Api::App
# Namespace for Sinatra extensions.
module Extensions
Dir.glob("#{__dir__}/extensions/*.rb").each { |f| require f[%r[(?<=lib/).+(?=\.rb$)]] }
end
end

View File

@ -1,7 +1,8 @@
require 'travis/api/app'
require 'travis/api/app/helpers/accept'
require 'travis/api/app/helpers/current_user'
require 'travis/api/app/helpers/db_follower'
require 'travis/api/app/helpers/flash'
require 'travis/api/app/helpers/mime_types'
require 'travis/api/app/helpers/respond_with'
class Travis::Api::App
# Namespace for helpers.
module Helpers
Dir.glob("#{__dir__}/helpers/*.rb").each { |f| require f[%r[(?<=lib/).+(?=\.rb$)]] }
end
end

View File

@ -53,8 +53,6 @@ class Travis::Api::App
if params
params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten]
quality = params.delete('q').to_f if params['q']
else
params = {}
end
if subtype =~ HEADER_FORMAT
@ -84,7 +82,7 @@ class Travis::Api::App
end
def accept_version
@accept_version ||= accept_entries.map(&:version).compact.first || DEFAULT_VERSION
@accept_version ||= request.accept.join =~ HEADER_FORMAT && "v#{$1}" || DEFAULT_VERSION
end
def accept_format

View File

@ -3,11 +3,5 @@ require 'travis/api/app'
class Travis::Api::App
# Superclass for all middleware.
class Middleware < Base
require 'travis/api/app/middleware/logging'
require 'travis/api/app/middleware/metriks'
require 'travis/api/app/middleware/rewrite'
require 'travis/api/app/middleware/scope_check'
require 'travis/api/app/middleware/skylight'
require 'travis/api/app/middleware/user_agent_tracker'
end
end

View File

@ -37,7 +37,7 @@ class Travis::Api::App
end
def mark_travis(agent)
command = agent.application.comment.detect { |c| c.start_with? "command " } if agent.application.comment
command = agent.application.comment.detect { |c| c.start_with? "command " }
if command
mark(:cli, :version, agent.version)

View File

@ -21,7 +21,7 @@ module Travis::Api::App::Responders
<updated><%= ::DateTime.parse(build.updated_at.to_s).rfc3339 %></updated>
<summary type="html">
&lt;p&gt;
<%= build.commit.message.encode(:xml => :text) if build.commit.message %> (<%= build.commit.committer_name %>)
<%= build.commit.message.encode(:xml => :text) %> (<%= build.commit.committer_name %>)
&lt;br/&gt;&lt;br/&gt;
State: <%= build.state %>
&lt;br/&gt;

View File

@ -1,5 +1,3 @@
require 'travis/api/serialize'
class Travis::Api::App
module Responders
class Json < Base
@ -48,7 +46,7 @@ class Travis::Api::App
if defined?(@builder)
@builder
else
@builder = Travis::Api::Serialize.builder(resource, { :version => version }.merge(options))
@builder = Travis::Api.builder(resource, { :version => version }.merge(options))
end
end

View File

@ -1,115 +0,0 @@
require 'rack/attack'
require 'netaddr'
class Rack::Attack
class Request
TOKEN = 'travis.access_token'.freeze
def travis_token
env.fetch(TOKEN)
end
def authenticated?
env.include? TOKEN
end
def identifier
authenticated? ? travis_token.to_s : ip
end
end
def self.bantime(value)
case Travis.env
when "production" then value
when "staging" then 10 # ban for 10 seconds on staging
else 1
end
end
POST_SAFELIST = [
"/auth/handshake",
"/auth/post_message",
"/auth/post_message/iframe"
]
GITHUB_CIDR = NetAddr::CIDR.create('192.30.252.0/22')
safelist('safelist build status images') do |request|
/\.(png|svg)$/.match(request.path)
end
# https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-safelist/
safelist('safelist anything coming from github') do |request|
request.ip && GITHUB_CIDR.contains?(request.ip)
end
####
# Whitelisted IP addresses
safelist('safelist client requesting from redis') do |request|
# TODO: deprecate :api_whitelisted_ips in favour of api_safelisted_ips
Travis.redis.sismember(:api_whitelisted_ips, request.ip) || Travis.redis.sismember(:api_safelisted_ips, request.ip)
end
####
# Ban based on: IP address
# Ban time: indefinite
# Ban after: manually banned
blocklist('block client requesting from redis') do |request|
# TODO: deprecate :api_blacklisted_ips in favour of api_blocklisted_ips
Travis.redis.sismember(:api_blacklisted_ips, request.ip) || Travis.redis.sismember(:api_blocklisted_ips, request.ip)
end
####
# Ban based on: IP address or access token
# Ban time: 5 hours
# Ban after: 10 POST requests within five minutes to /auth/github
blocklist('hammering /auth/github') do |request|
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 2, findtime: 5.minutes, bantime: bantime(5.hours)) do
request.post? and request.path == '/auth/github'
end
end
####
# Ban based on: IP address or access token
# Ban time: 1 hour
# Ban after: 10 POST requests within 30 seconds
blocklist('spamming with POST requests') do |request|
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 10, findtime: 30.seconds, bantime: bantime(1.hour)) do
request.post? and not POST_SAFELIST.include? request.path
end
end
###
# Throttle: unauthenticated requests to /auth/github - 1 per minute
# Scoped by: IP address
throttle('req/ip/1min', limit: 1, period: 1.minute) do |request|
request.ip unless request.authenticated? and request.path == '/auth/github'
end
###
# Throttle: unauthenticated requests - 500 per minute
# Scoped by: IP address
throttle('req/ip/1min', limit: 500, period: 1.minute) do |request|
request.ip unless request.authenticated?
end
###
# Throttle: authenticated requests - 2000 per minute
# Scoped by: access token
throttle('req/token/1min', limit: 2000, period: 1.minute) do |request|
request.identifier
end
if ENV["MEMCACHIER_SERVERS"]
cache.store = Dalli::Client.new(
ENV["MEMCACHIER_SERVERS"].split(","),
username: ENV["MEMCACHIER_USERNAME"],
password: ENV["MEMCACHIER_PASSWORD"],
failover: true,
socket_timeout: 1.5,
socket_failure_delay: 0.2)
else
cache.store = ActiveSupport::Cache::MemoryStore.new
end
end

View File

@ -1,59 +0,0 @@
module Travis
module Enqueue
module Services
class CancelModel
attr_reader :current_user, :target
def initialize(current_user, params)
@current_user = current_user
@params = params
target
end
def messages
messages = []
messages << { :notice => "The #{type} was successfully cancelled." } if can_cancel?
messages << { :error => "You are not authorized to cancel this #{type}." } unless authorized?
messages << { :error => "The #{type} could not be cancelled." } unless build.cancelable?
messages
end
def push(event, payload)
# target may have been retrieved with a :join query, so we need to reset the readonly status
if can_cancel?
::Sidekiq::Client.push(
'queue' => 'hub',
'class' => 'Travis::Hub::Sidekiq::Worker',
#'args' => ["#{type}:cancel", @params]
'args' => [event, payload]
)
end
end
def type
@type ||= @params[:build_id] ? :build : :job
end
def target
if type == :build
@target = Build.find(@params[:build_id])
else
@target = Job.find(@params[:job_id])
end
end
def can_cancel?
authorized? && target.cancelable?
end
# check on web
def authorized?
current_user.permission?(:pull, :repository_id => target.repository_id)
end
end
end
end
end

View File

@ -1,64 +0,0 @@
module Travis
module Enqueue
module Services
class RestartModel
attr_reader :current_user, :target
def initialize(current_user, params)
@current_user = current_user
@params = params
target
end
def push(event, payload)
if current_user && target && accept?
::Sidekiq::Client.push(
'queue' => 'hub',
'class' => 'Travis::Hub::Sidekiq::Worker',
'args' => [event, payload]
)
end
end
def accept?
current_user && permission? && resetable?
end
def messages
messages = []
messages << { notice: "The #{type} was successfully restarted." } if accept?
messages << { error: 'You do not seem to have sufficient permissions.' } unless permission?
messages << { error: "This #{type} currently can not be restarted." } unless resetable?
messages
end
def type
@type ||= @params[:build_id] ? :build : :job
end
def target
if type == :build
@target = Build.find(@params[:build_id])
else
@target = Job.find(@params[:job_id])
end
end
private
def permission?
current_user.permission?(required_role, repository_id: target.repository_id)
end
def resetable?
target.resetable?
end
def required_role
Travis.config.roles.reset_model
end
end
end
end
end

View File

@ -1,68 +0,0 @@
require 'travis/api/serialize/formats'
require 'travis/api/serialize/v0'
require 'travis/api/serialize/v1'
module Travis
module Api
module Serialize
DEFAULT_VERSION = 'v2'
class << self
def data(resource, options = {})
new(resource, options).data
end
def builder(resource, options = {})
target = (options[:for] || 'http').to_s.camelize
version = (options[:version] || default_version(options)).to_s.camelize
type = (options[:type] || type_for(resource)).to_s.camelize.split('::')
([version, target] + type).inject(self) do |const, name|
begin
if const && const.const_defined?(name.to_s.camelize, false)
const.const_get(name, false)
else
nil
end
rescue NameError
nil
end
end
end
def new(resource, options = {})
builder = builder(resource, options) || raise(ArgumentError, "cannot serialize #{resource.inspect}, options: #{options.inspect}")
builder.new(resource, options[:params] || {})
end
private
def type_for(resource)
if arel_relation?(resource)
type = resource.klass.name.pluralize
else
type = resource.class
type = type.base_class if active_record?(type)
type = type.name
end
type.split('::').last
end
def arel_relation?(object)
object.respond_to?(:klass)
end
def active_record?(object)
object.respond_to?(:base_class)
end
def default_version(options)
if options[:for].to_s.downcase == "pusher"
"v0"
else
DEFAULT_VERSION
end
end
end
end
end
end

View File

@ -1,11 +0,0 @@
module Travis
module Api
module Serialize
module Formats
def format_date(date)
date && date.strftime('%Y-%m-%dT%H:%M:%SZ')
end
end
end
end
end

View File

@ -1,25 +0,0 @@
require 'active_model_serializers'
module Travis
module Api
module Serialize
class ObjectSerializer < ActiveModel::Serializer
def data
as_json
end
end
class ArraySerializer < ActiveModel::ArraySerializer
def data
as_json
end
def initialize(resource, options)
options[:each_serializer] ||= V2::Http.const_get(options[:root].to_s.singularize.camelize)
super(resource, options)
end
end
end
end
end

View File

@ -1,6 +0,0 @@
# V0 is an internal api that we can change at any time
require 'travis/api/serialize/v0/event'
require 'travis/api/serialize/v0/notification'
require 'travis/api/serialize/v0/pusher'
require 'travis/api/serialize/v0/worker'

View File

@ -1,2 +0,0 @@
require 'travis/api/serialize/v0/event/build'
require 'travis/api/serialize/v0/event/job'

View File

@ -1,96 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Event
class Build
include Formats
attr_reader :build, :repository, :request, :commit, :options
def initialize(build, options = {})
@build = build
@repository = build.repository
@request = build.request
@commit = build.commit
# @options = options
end
def data(extra = {})
{
'repository' => repository_data,
'request' => request_data,
'commit' => commit_data,
'build' => build_data,
'jobs' => build.matrix.map { |job| job_data(job) }
}
end
private
def build_data
{
'id' => build.id,
'repository_id' => build.repository_id,
'commit_id' => build.commit_id,
'number' => build.number,
'pull_request' => build.pull_request?,
'pull_request_number' => build.pull_request_number,
'config' => build.config.try(:except, :source_key),
'state' => build.state.to_s,
'previous_state' => build.previous_state.to_s,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'job_ids' => build.matrix_ids
}
end
def repository_data
{
'id' => repository.id,
'key' => repository.key.try(:public_key),
'slug' => repository.slug,
'name' => repository.name,
'owner_email' => repository.owner_email,
'owner_avatar_url' => repository.owner.try(:avatar_url)
}
end
def request_data
{
'token' => request.token,
'head_commit' => (request.head_commit || '')
}
end
def commit_data
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
}
end
def job_data(job)
{
'id' => job.id,
'number' => job.number,
'state' => job.state.to_s,
'tags' => job.tags
}
end
end
end
end
end
end
end

View File

@ -1,37 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Event
class Job
include Formats
attr_reader :job
def initialize(job, options = {})
@job = job
# @options = options
end
def data(extra = {})
{
'job' => job_data,
}
end
private
def job_data
{
'queue' => job.queue,
'created_at' => job.created_at,
'started_at' => job.started_at,
'finished_at' => job.finished_at,
}
end
end
end
end
end
end
end

View File

@ -1,3 +0,0 @@
require 'travis/api/serialize/v0/notification/build'
require 'travis/api/serialize/v0/notification/repository'
require 'travis/api/serialize/v0/notification/user'

View File

@ -1,29 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Notification
class Build
attr_reader :build
def initialize(build, options = {})
@build = build
end
def data
{
'build' => build_data
}
end
def build_data
{
'id' => build.id
}
end
end
end
end
end
end
end

View File

@ -1,30 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Notification
class Repository
attr_reader :repository
def initialize(repository, options = {})
@repository = repository
end
def data
{
'repository' => repository_data
}
end
def repository_data
{
'id' => repository.id,
'slug' => repository.slug
}
end
end
end
end
end
end
end

View File

@ -1,30 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Notification
class User
attr_reader :user
def initialize(user, options = {})
@user = user
end
def data
{
'user' => user_data
}
end
def user_data
{
'id' => user.id,
'login' => user.login
}
end
end
end
end
end
end
end

View File

@ -1,3 +0,0 @@
require 'travis/api/serialize/v0/pusher/annotation'
require 'travis/api/serialize/v0/pusher/build'
require 'travis/api/serialize/v0/pusher/job'

View File

@ -1,35 +0,0 @@
require 'travis/api/serialize/v0/pusher/annotation/created'
require 'travis/api/serialize/v0/pusher/annotation/updated'
module Travis
module Api
module Serialize
module V0
module Pusher
class Annotation
include Formats
attr_reader :annotation
def initialize(annotation, options = {})
@annotation = annotation
end
def data
{
"annotation" => {
"id" => annotation.id,
"job_id" => annotation.job_id,
"description" => annotation.description,
"url" => annotation.url,
"status" => annotation.status,
"provider_name" => annotation.annotation_provider.name,
}
}
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Annotation
class Created < Annotation
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Annotation
class Updated < Annotation
end
end
end
end
end
end
end

View File

@ -1,112 +0,0 @@
require 'travis/api/serialize/v0/pusher/build/canceled'
require 'travis/api/serialize/v0/pusher/build/created'
require 'travis/api/serialize/v0/pusher/build/received'
require 'travis/api/serialize/v0/pusher/build/started'
require 'travis/api/serialize/v0/pusher/build/finished'
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
include Formats
attr_reader :build, :options
def initialize(build, options = {})
@build = build
@options = options
end
def data
{
'build' => build_data(build),
'commit' => commit_data(build.commit),
'repository' => repository_data(build.repository)
}
end
private
def build_data(build)
commit = build.commit
{
'id' => build.id,
'repository_id' => build.repository_id,
'commit_id' => build.commit_id,
'number' => build.number,
'pull_request' => build.pull_request?,
'pull_request_title' => build.pull_request_title,
'pull_request_number' => build.pull_request_number,
'state' => build.state.to_s,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'job_ids' => build.matrix_ids,
'event_type' => build.event_type,
# this is a legacy thing, we should think about removing it
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'compare_url' => commit.compare_url,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email
}
end
def commit_data(commit)
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
}
end
def repository_data(repository)
{
'id' => repository.id,
'slug' => repository.slug,
'description' => repository.description,
'private' => repository.private,
'last_build_id' => repository.last_build_id,
'last_build_number' => repository.last_build_number,
'last_build_state' => repository.last_build_state.to_s,
'last_build_duration' => repository.last_build_duration,
'last_build_language' => nil,
'last_build_started_at' => format_date(repository.last_build_started_at),
'last_build_finished_at' => format_date(repository.last_build_finished_at),
'github_language' => repository.github_language,
'default_branch' => {
'name' => repository.default_branch,
'last_build_id' => last_build_on_default_branch_id(repository)
},
'active' => repository.active,
'current_build_id' => repository.current_build_id
}
end
def last_build_on_default_branch_id(repository)
default_branch = Branch.where(repository_id: repository.id, name: repository.default_branch).first
if default_branch
default_branch.last_build_id
end
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Canceled < Build
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Created < Build
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Finished < Build
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Received < Build
end
end
end
end
end
end
end

View File

@ -1,49 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Received < Build
class Job
include Formats, V1::Helpers::Legacy
attr_reader :job, :commit
def initialize(job)
@job = job
@commit = job.commit
end
def data
{
'id' => job.id,
'repository_id' => job.repository_id,
'repository_private' => repository.private,
'parent_id' => job.source_id,
'number' => job.number,
'state' => job.state.to_s,
'result' => legacy_job_result(job),
'config' => job.obfuscated_config,
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'compare_url' => commit.compare_url,
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'allow_failure' => job.allow_failure
}
end
end
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Started < Build
end
end
end
end
end
end
end

View File

@ -1,49 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Build
class Started < Build
class Job
include Formats, V1::Helpers::Legacy
attr_reader :job, :commit
def initialize(job)
@job = job
@commit = job.commit
end
def data
{
'id' => job.id,
'repository_id' => job.repository_id,
'repository_private' => repository.private,
'parent_id' => job.source_id,
'number' => job.number,
'state' => job.state.to_s,
'result' => legacy_job_result(job),
'config' => job.obfuscated_config,
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'compare_url' => commit.compare_url,
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'allow_failure' => job.allow_failure
}
end
end
end
end
end
end
end
end
end

View File

@ -1,69 +0,0 @@
require 'travis/api/serialize/v0/pusher/job/canceled'
require 'travis/api/serialize/v0/pusher/job/created'
require 'travis/api/serialize/v0/pusher/job/log'
require 'travis/api/serialize/v0/pusher/job/received'
require 'travis/api/serialize/v0/pusher/job/started'
require 'travis/api/serialize/v0/pusher/job/finished'
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
include Formats
attr_reader :job, :options
def initialize(job, options = {})
@job = job
@options = options
end
def data
job_data(job).merge(
'commit' => commit_data(job.commit)
)
end
private
def job_data(job)
{
'id' => job.id,
'repository_id' => job.repository_id,
'repository_slug' => job.repository.slug,
'repository_private' => job.repository.private,
'build_id' => job.source_id,
'commit_id' => job.commit_id,
'log_id' => job.log_id,
'number' => job.number,
'state' => job.state.to_s,
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'queue' => job.queue,
'allow_failure' => job.allow_failure,
'annotation_ids' => job.annotation_ids
}
end
def commit_data(commit)
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
}
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Canceled < Job
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Created < Job
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Finished < Job
end
end
end
end
end
end
end

View File

@ -1,32 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Log
attr_reader :job, :options
def initialize(job, options = {})
@job = job
@options = options
end
def data
{
'id' => job.id,
'build_id' => job.source_id,
'repository_id' => job.repository_id,
'repository_private' => repository.private,
'_log' => options[:_log],
'number' => options[:number],
'final' => options[:final]
}
end
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Received < Job
end
end
end
end
end
end
end

View File

@ -1,14 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Pusher
class Job
class Started < Job
end
end
end
end
end
end
end

View File

@ -1 +0,0 @@
require 'travis/api/serialize/v0/worker/job'

View File

@ -1,35 +0,0 @@
require 'travis/api/serialize/v0/worker/job/test'
module Travis
module Api
module Serialize
module V0
module Worker
class Job
attr_reader :job
def initialize(job, options = {})
@job = job
end
def commit
job.commit
end
def repository
job.repository
end
def request
build.request
end
def build
job.source
end
end
end
end
end
end
end

View File

@ -1,120 +0,0 @@
module Travis
module Api
module Serialize
module V0
module Worker
class Job
class Test < Job
include Formats
def data
{
'type' => 'test',
# TODO legacy. remove this once workers respond to a 'job' key
'build' => job_data,
'job' => job_data,
'source' => build_data,
'repository' => repository_data,
'pull_request' => commit.pull_request? ? pull_request_data : false,
'config' => job.decrypted_config,
'queue' => job.queue,
'uuid' => Travis.uuid,
'ssh_key' => ssh_key,
'env_vars' => env_vars,
'timeouts' => timeouts
}
end
def build_data
{
'id' => build.id,
'number' => build.number
}
end
def job_data
data = {
'id' => job.id,
'number' => job.number,
'commit' => commit.commit,
'commit_range' => commit.range,
'commit_message' => commit.message,
'branch' => commit.branch,
'ref' => commit.pull_request? ? commit.ref : nil,
'state' => job.state.to_s,
'secure_env_enabled' => job.secure_env_enabled?
}
data['tag'] = request.tag_name if include_tag_name?
data['pull_request'] = commit.pull_request? ? commit.pull_request_number : false
data
end
def repository_data
{
'id' => repository.id,
'slug' => repository.slug,
'github_id' => repository.github_id,
'source_url' => repository.source_url,
'api_url' => repository.api_url,
'last_build_id' => repository.last_build_id,
'last_build_number' => repository.last_build_number,
'last_build_started_at' => format_date(repository.last_build_started_at),
'last_build_finished_at' => format_date(repository.last_build_finished_at),
'last_build_duration' => repository.last_build_duration,
'last_build_state' => repository.last_build_state.to_s,
'description' => repository.description,
'default_branch' => repository.default_branch
}
end
def pull_request_data
{
'number' => commit.pull_request_number,
'head_repo' => request.head_repo,
'base_repo' => request.base_repo,
'head_branch' => request.head_branch,
'base_branch' => request.base_branch
}
end
def ssh_key
nil
end
def env_vars
vars = settings.env_vars
vars = vars.public unless job.secure_env_enabled?
vars.map do |var|
{
'name' => var.name,
'value' => var.value.decrypt,
'public' => var.public
}
end
end
def timeouts
{ 'hard_limit' => timeout(:hard_limit), 'log_silence' => timeout(:log_silence) }
end
def timeout(type)
timeout = settings.send(:"timeout_#{type}")
timeout = timeout * 60 if timeout # worker handles timeouts in seconds
timeout
end
def include_tag_name?
Travis.config.include_tag_name_in_worker_payload && request.tag_name.present?
end
def settings
repository.settings
end
end
end
end
end
end
end
end

View File

@ -1,4 +0,0 @@
require 'travis/api/serialize/v1/archive'
require 'travis/api/serialize/v1/http'
require 'travis/api/serialize/v1/helpers'
require 'travis/api/serialize/v1/webhook'

View File

@ -1 +0,0 @@
require 'travis/api/serialize/v1/archive/build'

View File

@ -1,52 +0,0 @@
require 'travis/api/serialize/v1/archive/build/job'
module Travis
module Api
module Serialize
module V1
module Archive
class Build
include Formats
attr_reader :build, :commit, :repository
def initialize(build, options = {})
@build = build
@commit = build.commit
@repository = build.repository
end
def data
{
'id' => build.id,
'number' => build.number,
'config' => build.obfuscated_config.stringify_keys,
'result' => 0,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'matrix' => build.matrix.map { |job| Job.new(job).data },
'repository' => repository_data
}
end
def repository_data
{
'id' => repository.id,
'slug' => repository.slug
}
end
end
end
end
end
end
end

View File

@ -1,33 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Archive
class Build
class Job
include Formats
attr_reader :job, :commit
def initialize(job)
@job = job
@commit = job.commit
end
def data
{
'id' => job.id,
'number' => job.number,
'config' => job.obfuscated_config,
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'log' => job.log_content
}
end
end
end
end
end
end
end
end

View File

@ -1 +0,0 @@
require 'travis/api/serialize/v1/helpers/legacy'

View File

@ -1,36 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Helpers
module Legacy
RESULTS = {
passed: 0,
failed: 1
}
def legacy_repository_last_build_result(repository)
RESULTS[repository.last_build_state.try(:to_sym)]
end
def legacy_build_state(build)
build.finished? ? 'finished' : build.state.to_s
end
def legacy_build_result(build)
RESULTS[build.state.try(:to_sym)]
end
def legacy_job_state(job)
job.finished? ? 'finished' : job.state.to_s
end
def legacy_job_result(job)
RESULTS[job.state.try(:to_sym)]
end
end
end
end
end
end
end

View File

@ -1,9 +0,0 @@
require 'travis/api/serialize/v1/http/branches'
require 'travis/api/serialize/v1/http/build'
require 'travis/api/serialize/v1/http/builds'
require 'travis/api/serialize/v1/http/hooks'
require 'travis/api/serialize/v1/http/job'
require 'travis/api/serialize/v1/http/jobs'
require 'travis/api/serialize/v1/http/repositories'
require 'travis/api/serialize/v1/http/repository'
require 'travis/api/serialize/v1/http/user'

View File

@ -1,45 +0,0 @@
require 'travis/api/serialize/v1/helpers/legacy'
module Travis
module Api
module Serialize
module V1
module Http
class Branches
include Formats, Helpers::Legacy
attr_reader :builds, :options
def initialize(builds, options = {})
builds = builds.last_finished_builds_by_branches if builds.is_a?(Repository) # TODO remove, bc
@builds = builds
end
def cache_key
"branches-#{builds.map(&:id).join('-')}"
end
def updated_at
builds.compact.map(&:finished_at).compact.sort.first
end
def data
builds.compact.map do |build|
{
'repository_id' => build.repository_id,
'build_id' => build.id,
'commit' => build.commit.commit,
'branch' => build.commit.branch,
'message' => build.commit.message,
'result' => legacy_build_result(build),
'finished_at' => format_date(build.finished_at),
'started_at' => format_date(build.started_at)
}
end
end
end
end
end
end
end
end

View File

@ -1,49 +0,0 @@
require 'travis/api/serialize/v1/http/build/job'
module Travis
module Api
module Serialize
module V1
module Http
class Build
include Formats, Helpers::Legacy
attr_reader :build, :commit, :request
def initialize(build, options = {})
@build = build
@commit = build.commit
@request = build.request
end
def data
{
'id' => build.id,
'repository_id' => build.repository_id,
'number' => build.number,
'config' => build.obfuscated_config.stringify_keys,
'state' => legacy_build_state(build),
'result' => legacy_build_result(build),
'status' => legacy_build_result(build),
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
'event_type' => build.event_type,
'matrix' => build.matrix.map { |job| Job.new(job).data },
}
end
end
end
end
end
end
end

View File

@ -1,34 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Http
class Build
class Job
include Formats, Helpers::Legacy
attr_reader :job
def initialize(job)
@job = job
end
def data
{
'id' => job.id,
'repository_id' => job.repository_id,
'number' => job.number,
'config' => job.obfuscated_config.stringify_keys,
'result' => legacy_job_result(job),
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'allow_failure' => job.allow_failure
}
end
end
end
end
end
end
end
end

View File

@ -1,40 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Http
class Builds
include Formats, Helpers::Legacy
attr_reader :builds
def initialize(builds, options = {})
@builds = builds
end
def data
builds.map { |build| build_data(build) }
end
def build_data(build)
{
'id' => build.id,
'repository_id' => build.repository_id,
'number' => build.number,
'state' => legacy_build_state(build),
'result' => legacy_build_result(build),
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'commit' => build.commit.commit,
'branch' => build.commit.branch,
'message' => build.commit.message,
'event_type' => build.event_type,
}
end
end
end
end
end
end
end

View File

@ -1,36 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Http
class Hooks
attr_reader :repos, :options
def initialize(repos, options = {})
@repos = repos
@options = options
end
def data
repos.map { |repo| repo_data(repo) }
end
private
def repo_data(repo)
{
'uid' => [repo.owner_name, repo.name].join(':'),
'url' => "https://github.com/#{repo.owner_name}/#{repo.name}",
'name' => repo.name,
'owner_name' => repo.owner_name,
'description' => repo.description,
'active' => repo.active,
'private' => repo.private
}
end
end
end
end
end
end
end

View File

@ -1,36 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Http
class Jobs
include Formats, Helpers::Legacy
attr_reader :jobs
def initialize(jobs, options = {})
@jobs = jobs
end
def data
jobs.map { |job| job_data(job) }
end
def job_data(job)
commit = job.commit
{
'id' => job.id,
'repository_id' => job.repository_id,
'number' => job.number,
'state' => legacy_job_state(job),
'queue' => job.queue,
'allow_failure' => job.allow_failure
}
end
end
end
end
end
end
end

View File

@ -1,33 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Http
class User
include Formats
attr_reader :user, :options
def initialize(user, options = {})
@user = user
@options = options
end
def data
{
'login' => user.login,
'name' => user.name,
'email' => user.email,
'gravatar_id' => user.gravatar_id,
'locale' => user.locale,
'is_syncing' => user.is_syncing,
'synced_at' => format_date(user.synced_at)
}
end
end
end
end
end
end
end

View File

@ -1 +0,0 @@
require 'travis/api/serialize/v1/webhook/build'

View File

@ -1,29 +0,0 @@
require 'travis/api/serialize/v1/webhook/build/finished'
module Travis
module Api
module Serialize
module V1
module Webhook
class Build
attr_reader :build, :commit, :request, :repository, :options
def initialize(build, options = {})
@build = build
@commit = build.commit
@request = build.request
@repository = build.repository
@options = options
end
private
def build_url
["https://#{Travis.config.host}", repository.slug, 'builds', build.id].join('/')
end
end
end
end
end
end
end

View File

@ -1,72 +0,0 @@
require 'travis/api/serialize/v1/webhook/build/finished/job'
module Travis
module Api
module Serialize
module V1
module Webhook
class Build
class Finished < Build
include Formats
def data
data = {
'id' => build.id,
'repository' => repository_data,
'number' => build.number,
'config' => build.obfuscated_config.stringify_keys,
'status' => build.result,
'result' => build.result,
'status_message' => result_message,
'result_message' => result_message,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'build_url' => build_url,
'commit_id' => commit.id,
'commit' => commit.commit,
'base_commit' => request.base_commit,
'head_commit' => request.head_commit,
'branch' => commit.branch,
'message' => commit.message,
'compare_url' => commit.compare_url,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'matrix' => build.matrix.map { |job| Job.new(job, options).data },
'type' => build.event_type,
'state' => build.state.to_s,
'pull_request' => build.pull_request?,
'pull_request_number' => build.pull_request_number,
'pull_request_title' => build.pull_request_title,
'tag' => request.tag_name
}
if commit.pull_request?
data['pull_request_number'] = commit.pull_request_number
end
data
end
def repository_data
{
'id' => repository.id,
'name' => repository.name,
'owner_name' => repository.owner_name,
'url' => repository.url
}
end
def result_message
@result_message ||= ::Build::ResultMessage.new(build).short
end
end
end
end
end
end
end
end

View File

@ -1,52 +0,0 @@
module Travis
module Api
module Serialize
module V1
module Webhook
class Build
class Finished < Build
class Job
include Formats
attr_reader :job, :commit, :options
def initialize(job, options = {})
@job = job
@commit = job.commit
@options = options
end
def data
data = {
'id' => job.id,
'repository_id' => job.repository_id,
'parent_id' => job.source_id,
'number' => job.number,
'state' => job.finished? ? 'finished' : job.state.to_s,
'config' => job.obfuscated_config,
'status' => job.result,
'result' => job.result,
'commit' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'compare_url' => commit.compare_url,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'allow_failure' => job.allow_failure
}
data['log'] = job.log_content || '' if options[:include_logs]
data['started_at'] = format_date(job.started_at) if job.started?
data['finished_at'] = format_date(job.finished_at) if job.finished?
data
end
end
end
end
end
end
end
end
end

View File

@ -1 +0,0 @@
require 'travis/api/serialize/v2/http'

View File

@ -1,24 +0,0 @@
require 'travis/api/serialize/serializer'
require 'travis/api/serialize/v2/http/accounts'
require 'travis/api/serialize/v2/http/annotations'
require 'travis/api/serialize/v2/http/broadcasts'
require 'travis/api/serialize/v2/http/branch'
require 'travis/api/serialize/v2/http/branches'
require 'travis/api/serialize/v2/http/build'
require 'travis/api/serialize/v2/http/builds'
require 'travis/api/serialize/v2/http/caches'
require 'travis/api/serialize/v2/http/hooks'
require 'travis/api/serialize/v2/http/job'
require 'travis/api/serialize/v2/http/jobs'
require 'travis/api/serialize/v2/http/log'
require 'travis/api/serialize/v2/http/permissions'
require 'travis/api/serialize/v2/http/repositories'
require 'travis/api/serialize/v2/http/repository'
require 'travis/api/serialize/v2/http/requests'
require 'travis/api/serialize/v2/http/request'
require 'travis/api/serialize/v2/http/ssl_key'
require 'travis/api/serialize/v2/http/env_var'
require 'travis/api/serialize/v2/http/env_vars'
require 'travis/api/serialize/v2/http/user'
require 'travis/api/serialize/v2/http/validation_error'
require 'travis/api/serialize/v2/http/ssh_key'

View File

@ -1,44 +0,0 @@
require 'travis/api/serialize/formats'
module Travis
module Api
module Serialize
module V2
module Http
class Accounts
include Formats
attr_reader :accounts, :options
def initialize(accounts, options = {})
@accounts = accounts
@options = options
end
def data
{
:accounts => accounts.map { |account| account_data(account) }
}
end
private
def account_data(account)
data = {
'id' => account.id,
'name' => account.name,
'login' => account.login,
'type' => account.type.underscore,
'repos_count' => account.repos_count
}
data['avatar_url'] = account.avatar_url if account.respond_to?(:avatar_url)
data
end
end
end
end
end
end
end

View File

@ -1,38 +0,0 @@
require 'travis/api/serialize/formats'
module Travis
module Api
module Serialize
module V2
module Http
class Annotations
include Formats
def initialize(annotations, options = {})
@annotations = annotations
end
def data
{
"annotations" => @annotations.map { |annotation| build_annotation(annotation) },
}
end
private
def build_annotation(annotation)
{
"id" => annotation.id,
"job_id" => annotation.job_id,
"description" => annotation.description,
"url" => annotation.url,
"status" => annotation.status,
"provider_name" => annotation.annotation_provider.name,
}
end
end
end
end
end
end
end

View File

@ -1,31 +0,0 @@
require 'travis/api/serialize/formats'
require 'travis/api/serialize/v2/http/branches'
module Travis
module Api
module Serialize
module V2
module Http
class Branch < Branches
include Formats
attr_reader :build, :commit, :options
def initialize(build, options = {})
@build = build
@commit = build.commit
@options = options
end
def data
{
'branch' => build_data(build),
'commit' => commit_data(commit)
}
end
end
end
end
end
end
end

View File

@ -1,64 +0,0 @@
require 'travis/api/serialize/formats'
module Travis
module Api
module Serialize
module V2
module Http
class Branches
include Formats
attr_reader :builds, :commits, :options
def initialize(builds, options = {})
builds = builds.last_finished_builds_by_branches if builds.is_a?(Repository) # TODO remove, bc
@builds = builds
@commits = builds.map(&:commit)
@options = options
end
def data
{
'branches' => builds.map { |build| build_data(build) },
'commits' => commits.map { |commit| commit_data(commit) }
}
end
private
def build_data(build)
{
'id' => build.id,
'repository_id' => build.repository_id,
'commit_id' => build.commit_id,
'number' => build.number,
'config' => build.obfuscated_config.stringify_keys,
'state' => build.state.to_s,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'job_ids' => build.matrix.map { |job| job.id },
'pull_request' => build.pull_request?
}
end
def commit_data(commit)
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
}
end
end
end
end
end
end
end

View File

@ -1,33 +0,0 @@
module Travis
module Api
module Serialize
module V2
module Http
class Broadcasts
attr_reader :broadcasts, :options
def initialize(broadcasts, options = {})
@broadcasts = broadcasts
@options = options
end
def data
{
'broadcasts' => broadcasts.map { |broadcast| broadcast_data(broadcast) }
}
end
private
def broadcast_data(broadcast)
{
'id' => broadcast.id,
'message' => broadcast.message
}
end
end
end
end
end
end
end

View File

@ -1,97 +0,0 @@
require 'travis/api/serialize/formats'
module Travis
module Api
module Serialize
module V2
module Http
class Build
include Formats
attr_reader :build, :options
def initialize(build, options = {})
options[:include_jobs] = true unless options.key?(:include_jobs)
@build = build
@options = options
end
def data
{
'build' => build_data(build),
'commit' => commit_data(build.commit, build.repository),
'jobs' => options[:include_jobs] ? build.matrix.map { |job| job_data(job) } : [],
'annotations' => options[:include_jobs] ? Annotations.new(annotations(build), @options).data["annotations"] : [],
}
end
private
def build_data(build)
{
'id' => build.id,
'repository_id' => build.repository_id,
'commit_id' => build.commit_id,
'number' => build.number,
'event_type' => build.event_type,
'pull_request' => build.pull_request?,
'pull_request_title' => build.pull_request_title,
'pull_request_number' => build.pull_request_number,
'config' => build.obfuscated_config.stringify_keys,
'state' => build.state.to_s,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'job_ids' => build.matrix_ids
}
end
def commit_data(commit, repository)
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'branch_is_default' => branch_is_default(commit, repository),
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
}
end
def job_data(job)
{
'id' => job.id,
'repository_id' => job.repository_id,
'build_id' => job.source_id,
'commit_id' => job.commit_id,
'log_id' => job.log_id,
'state' => job.state.to_s,
'number' => job.number,
'config' => job.obfuscated_config.stringify_keys,
'started_at' => format_date(job.started_at),
'finished_at' => format_date(job.finished_at),
'queue' => job.queue,
'allow_failure' => job.allow_failure,
'tags' => job.tags,
'annotation_ids' => job.annotation_ids,
}
end
def branch_is_default(commit, repository)
repository.default_branch == commit.branch
end
def annotations(build)
build.matrix.map(&:annotations).flatten
end
end
end
end
end
end
end

View File

@ -1,71 +0,0 @@
require 'travis/api/serialize/formats'
module Travis
module Api
module Serialize
module V2
module Http
class Builds
include Formats
attr_reader :builds, :commits, :options
def initialize(builds, options = {})
@builds = builds
@commits = builds.map(&:commit)
@options = options
end
def data
{
'builds' => builds.map { |build| build_data(build) },
'commits' => commits.map { |commit| commit_data(commit) }
}
end
private
def build_data(build)
{
'id' => build.id,
'repository_id' => build.repository_id,
'commit_id' => build.commit_id,
'number' => build.number,
'event_type' => build.event_type,
'pull_request' => build.pull_request?,
'pull_request_title' => build.pull_request_title,
'pull_request_number' => build.pull_request_number,
'config' => build.obfuscated_config.stringify_keys,
'state' => build.state.to_s,
'started_at' => format_date(build.started_at),
'finished_at' => format_date(build.finished_at),
'duration' => build.duration,
'job_ids' => matrix_ids(build)
}
end
def matrix_ids(build)
build.cached_matrix_ids || build.matrix_ids
end
def commit_data(commit)
{
'id' => commit.id,
'sha' => commit.commit,
'branch' => commit.branch,
'message' => commit.message,
'committed_at' => format_date(commit.committed_at),
'author_name' => commit.author_name,
'author_email' => commit.author_email,
'committer_name' => commit.committer_name,
'committer_email' => commit.committer_email,
'compare_url' => commit.compare_url,
'pull_request_number' => commit.pull_request_number
}
end
end
end
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More