perkins 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.env.example +4 -0
- data/.gitignore +19 -0
- data/.pryrc +3 -0
- data/.rspec +2 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +71 -0
- data/Rakefile +28 -0
- data/TODO.md +4 -0
- data/bin/perkins +6 -0
- data/db/migrate/20150130143030_create_repo.rb +18 -0
- data/db/migrate/20150130143050_create_builds.rb +20 -0
- data/db/schema.rb +38 -0
- data/examples/config.rb +12 -0
- data/examples/database.yml +17 -0
- data/examples/mongo.yml +13 -0
- data/lib/core_ext/hash/compact.rb +8 -0
- data/lib/core_ext/hash/deep_merge.rb +15 -0
- data/lib/core_ext/hash/deep_symbolize_keys.rb +20 -0
- data/lib/core_ext/object/false.rb +5 -0
- data/lib/core_ext/string/indent.rb +5 -0
- data/lib/core_ext/string/unindent.rb +5 -0
- data/lib/perkins/.DS_Store +0 -0
- data/lib/perkins/application.rb +40 -0
- data/lib/perkins/assets/images/github.svg +4 -0
- data/lib/perkins/assets/images/spinner.svg +23 -0
- data/lib/perkins/assets/javascripts/app.js +9 -0
- data/lib/perkins/assets/javascripts/log_view.js.coffee +95 -0
- data/lib/perkins/assets/javascripts/perkings.js.coffee +40 -0
- data/lib/perkins/assets/javascripts/vendor/ansiparse.js +187 -0
- data/lib/perkins/assets/javascripts/vendor/jquery.timeago.js +189 -0
- data/lib/perkins/assets/javascripts/vendor/log.js +2 -0
- data/lib/perkins/assets/javascripts/vendor/minispade.js +55 -0
- data/lib/perkins/assets/stylesheets/app.css +2 -0
- data/lib/perkins/assets/stylesheets/log.css.scss +115 -0
- data/lib/perkins/assets/stylesheets/styles.css.scss +199 -0
- data/lib/perkins/auth/github.rb +181 -0
- data/lib/perkins/build/data/env.rb +84 -0
- data/lib/perkins/build/data/var.rb +60 -0
- data/lib/perkins/build/data.rb +167 -0
- data/lib/perkins/build/script/bundler.rb +76 -0
- data/lib/perkins/build/script/go.rb +100 -0
- data/lib/perkins/build/script/helpers.rb +39 -0
- data/lib/perkins/build/script/jdk.rb +43 -0
- data/lib/perkins/build/script/ruby.rb +31 -0
- data/lib/perkins/build/script/rvm.rb +73 -0
- data/lib/perkins/build/script/stages.rb +28 -0
- data/lib/perkins/build/script/templates/footer.sh +3 -0
- data/lib/perkins/build/script/templates/header.sh +201 -0
- data/lib/perkins/build/script/templates/xcode.sh +21 -0
- data/lib/perkins/build/script.rb +167 -0
- data/lib/perkins/build/shell/dsl.rb +104 -0
- data/lib/perkins/build/shell/node.rb +121 -0
- data/lib/perkins/build/shell.rb +16 -0
- data/lib/perkins/build.rb +27 -0
- data/lib/perkins/build_report.rb +11 -0
- data/lib/perkins/cli.rb +42 -0
- data/lib/perkins/commit.rb +30 -0
- data/lib/perkins/dsl/app_proxy.rb +23 -0
- data/lib/perkins/dsl.rb +12 -0
- data/lib/perkins/listener.rb +38 -0
- data/lib/perkins/logger.rb +12 -0
- data/lib/perkins/notifier.rb +5 -0
- data/lib/perkins/repo.rb +145 -0
- data/lib/perkins/runner.rb +124 -0
- data/lib/perkins/server.rb +314 -0
- data/lib/perkins/thor_utils.rb +79 -0
- data/lib/perkins/version.rb +3 -0
- data/lib/perkins/views/401.haml +1 -0
- data/lib/perkins/views/builds.haml +46 -0
- data/lib/perkins/views/index.haml +6 -0
- data/lib/perkins/views/layout.haml +53 -0
- data/lib/perkins/views/menu.haml +18 -0
- data/lib/perkins/views/orgs.haml +101 -0
- data/lib/perkins/views/profile.haml +31 -0
- data/lib/perkins/views/readme.md +20 -0
- data/lib/perkins/views/repos/config.haml +72 -0
- data/lib/perkins/views/repos/github.haml +76 -0
- data/lib/perkins/views/repos/menu.haml +17 -0
- data/lib/perkins/views/repos/repo.haml +64 -0
- data/lib/perkins/views/repos/spinner.haml +3 -0
- data/lib/perkins/webhooks/github.rb +12 -0
- data/lib/perkins/worker.rb +33 -0
- data/lib/perkins.rb +36 -0
- data/perkins.gemspec +52 -0
- data/spec/fixtures/.travis.yml +8 -0
- data/spec/fixtures/config.yml +6 -0
- data/spec/lib/build/build_spec.rb +58 -0
- data/spec/lib/commit_spec.rb +6 -0
- data/spec/lib/dsl_spec.rb +17 -0
- data/spec/lib/listener_spec.rb +30 -0
- data/spec/lib/repo_spec.rb +110 -0
- data/spec/lib/runner_spec.rb +76 -0
- data/spec/lib/server_spec.rb +108 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/auth.rb +30 -0
- data/spec/support/github_api.rb +177 -0
- metadata +503 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Perkins
|
5
|
+
%link{ href:"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" , rel:"stylesheet"}
|
6
|
+
|
7
|
+
%script{ src: "//code.jquery.com/jquery-2.1.1.min.js"}
|
8
|
+
%script{ src:"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"}
|
9
|
+
%link{:rel => "stylesheet", :href => "//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css"}/
|
10
|
+
|
11
|
+
%script{ src:"/assets/app.js"}
|
12
|
+
%link{ href:"/assets/app.css", media:"screen", rel:"stylesheet", type:"text/css"}
|
13
|
+
|
14
|
+
:javascript
|
15
|
+
minispade.require('log')
|
16
|
+
|
17
|
+
%body
|
18
|
+
= haml :menu
|
19
|
+
|
20
|
+
.container
|
21
|
+
#content
|
22
|
+
#left-wrap.col-sm-3
|
23
|
+
|
24
|
+
#sidebar.affix
|
25
|
+
#sidebar-header
|
26
|
+
.pull-right
|
27
|
+
%a.btn{href: "/me", title: "Add new repository"}
|
28
|
+
%span.glyphicon.glyphicon-plus
|
29
|
+
|
30
|
+
%h4.title Repos
|
31
|
+
|
32
|
+
%ul.nav.nav-stacked{style: "overflow:scroll;height:100%"}
|
33
|
+
- Perkins::Repo.added.all.each do |repo|
|
34
|
+
%li
|
35
|
+
%a{:href => "/repos/#{repo.name}"}
|
36
|
+
= repo.name
|
37
|
+
= haml :"repos/spinner", locals: {repo: repo}
|
38
|
+
|
39
|
+
#main-content.col-sm-9
|
40
|
+
= yield
|
41
|
+
|
42
|
+
#inner
|
43
|
+
|
44
|
+
.clearfix
|
45
|
+
#footer
|
46
|
+
-#= render 'footer'
|
47
|
+
.pull-right
|
48
|
+
Copyright © #{Time.now.year} Perkins
|
49
|
+
%strong
|
50
|
+
Redis connection:
|
51
|
+
%span
|
52
|
+
= $redis.client.host
|
53
|
+
= $redis.client.port
|
@@ -0,0 +1,18 @@
|
|
1
|
+
%nav.navbar.navbar-fixed-top{role:"navigation"}
|
2
|
+
.container
|
3
|
+
.navbar-header
|
4
|
+
%button.navbar-toggle{"data-target" => ".nav-collapse", "data-toggle" => "collapse", :type => "button"}
|
5
|
+
%span.sr-only
|
6
|
+
%span.icon-bar
|
7
|
+
%span.icon-bar
|
8
|
+
%span.icon-bar
|
9
|
+
.title
|
10
|
+
%a.navbar-brand{:href => "/#"} Perkins
|
11
|
+
|
12
|
+
.navbar-inner.pull-right
|
13
|
+
.nav-collapse
|
14
|
+
%ul.nav.navbar-nav
|
15
|
+
%li
|
16
|
+
%a{:href => "/"} Home
|
17
|
+
%li
|
18
|
+
%a{:href => "/logout"} Logout
|
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
#repo-menu.pull-right
|
3
|
+
%ul.nav.nav-pills{:role => "tablist"}
|
4
|
+
|
5
|
+
%li.dropdown
|
6
|
+
%a.dropdown-toggle{"aria-expanded" => "false", "data-toggle" => "dropdown", :href => "#", :role => "button"}
|
7
|
+
Orgs
|
8
|
+
%span.caret
|
9
|
+
%ul.dropdown-menu.dropdown-menu-right{:role => "menu"}
|
10
|
+
- orgs.each do |org|
|
11
|
+
%li
|
12
|
+
%a{:href => "/orgs/#{org[:login]}"}
|
13
|
+
= org[:login]
|
14
|
+
|
15
|
+
|
16
|
+
.title
|
17
|
+
%h1
|
18
|
+
%span#org-name
|
19
|
+
= org[:name]
|
20
|
+
|
21
|
+
%h5
|
22
|
+
%strong= org[:url]
|
23
|
+
|
24
|
+
.panel.panel-default
|
25
|
+
.panel-heading
|
26
|
+
Organization info:
|
27
|
+
|
28
|
+
.panel-body
|
29
|
+
.col-sm-3
|
30
|
+
|
31
|
+
%img.avatar{ src: avatar_url(org[:avatar_url], 80) }
|
32
|
+
|
33
|
+
.col-sm-3
|
34
|
+
|
35
|
+
%strong id:
|
36
|
+
= org[:id]
|
37
|
+
%br
|
38
|
+
|
39
|
+
%strong email:
|
40
|
+
= org[:email]
|
41
|
+
%br
|
42
|
+
|
43
|
+
%strong public repos:
|
44
|
+
= org[:public_repos]
|
45
|
+
|
46
|
+
|
47
|
+
.col-sm-3
|
48
|
+
|
49
|
+
%strong public gists:
|
50
|
+
= org[:public_gists]
|
51
|
+
%br
|
52
|
+
|
53
|
+
%strong followers:
|
54
|
+
= org[:followers]
|
55
|
+
%br
|
56
|
+
|
57
|
+
%strong following:
|
58
|
+
= org[:following]
|
59
|
+
|
60
|
+
.col-sm-3
|
61
|
+
|
62
|
+
%strong total private repos:
|
63
|
+
= org[:total_private_repos]
|
64
|
+
%br
|
65
|
+
|
66
|
+
%strong owned private repos:
|
67
|
+
= org[:owned_private_repos]
|
68
|
+
|
69
|
+
- if repos.any?
|
70
|
+
%h2 #{org[:name]} Repositories:
|
71
|
+
|
72
|
+
- repos.each do |repo|
|
73
|
+
%ul.list-group
|
74
|
+
%li.list-group-item
|
75
|
+
|
76
|
+
.pull-right
|
77
|
+
%a.btn{href: "/repos/add/#{repo["id"]}"}
|
78
|
+
ADD REPO
|
79
|
+
%span.btn.glyphicon.glyphicon-plus-sign
|
80
|
+
|
81
|
+
.row
|
82
|
+
%span.col-sm-2
|
83
|
+
%a{src: repo["owner"]["url"] }
|
84
|
+
%img{ src: repo["owner"]["avatar_url"], width: 120 }
|
85
|
+
%span.col-sm-7
|
86
|
+
.pull-right
|
87
|
+
|
88
|
+
- if repo["fork"]
|
89
|
+
%i.fa.fa-code-fork{title: "is a fork"}
|
90
|
+
|
91
|
+
- if repo["private"]
|
92
|
+
%i.fa.fa-lock{title: "is private"}
|
93
|
+
|
94
|
+
%h4= repo.name
|
95
|
+
%a{href: repo.url}
|
96
|
+
View on github
|
97
|
+
%i.fa.fa-external-link
|
98
|
+
%p.small= repo["description"]
|
99
|
+
|
100
|
+
|
101
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
- u = user.user
|
2
|
+
%p
|
3
|
+
.panel.panel-default
|
4
|
+
.panel-heading
|
5
|
+
Profile details
|
6
|
+
|
7
|
+
.panel-body
|
8
|
+
|
9
|
+
.col-sm-2
|
10
|
+
%img{:src => u[:avatar_url], :alt => "avatar" , width: 100}
|
11
|
+
|
12
|
+
.col-sm-8
|
13
|
+
%h2
|
14
|
+
= u[:name]
|
15
|
+
|
16
|
+
%h5
|
17
|
+
%strong= u[:company]
|
18
|
+
|
19
|
+
|
20
|
+
%h4 Select repos:
|
21
|
+
|
22
|
+
%ul
|
23
|
+
%li
|
24
|
+
%a{:href => "/myrepos"} #{u[:name]} repos
|
25
|
+
- user.orgs.each do |org|
|
26
|
+
%li
|
27
|
+
%a{ href: "/orgs/#{org[:login]}" }
|
28
|
+
= org[:login]
|
29
|
+
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Welcome to Perkins CI - thin CI for ruby
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
###Configure:
|
6
|
+
```ruby
|
7
|
+
Perkins.application() do |app|
|
8
|
+
app.redis = Redis.new
|
9
|
+
app.server = { host: "localhost", port:1234 }
|
10
|
+
app.repo("lazy_high_charts") do |repo|
|
11
|
+
repo.url = "git@github.com:michelson/lazy_high_charts.git"
|
12
|
+
repo.name = "lazy_high_charts"
|
13
|
+
repo.working_dir = "/tmp/"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
###Run server:
|
19
|
+
|
20
|
+
perkins server examples/config.rb --port=3000
|
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
= haml :"repos/menu" , locals:{ repo: repo, active: "config", build: nil}
|
4
|
+
|
5
|
+
.title
|
6
|
+
%h2
|
7
|
+
%span#repo-name= repo.name
|
8
|
+
= haml :"repos/spinner", locals: {repo: repo}
|
9
|
+
|
10
|
+
%h5
|
11
|
+
%strong= repo.url
|
12
|
+
|
13
|
+
|
14
|
+
.panel.panel-default
|
15
|
+
.panel-heading
|
16
|
+
Config Post Hook
|
17
|
+
|
18
|
+
.panel-body
|
19
|
+
|
20
|
+
- if hook.present?
|
21
|
+
.col-sm-12
|
22
|
+
|
23
|
+
.pull-right
|
24
|
+
.badge
|
25
|
+
#{hook["active"] ? "active" : "disabled"}
|
26
|
+
%h2
|
27
|
+
%a{ href: hook["url"]}
|
28
|
+
= hook["name"]
|
29
|
+
\-
|
30
|
+
= hook["id"]
|
31
|
+
|
32
|
+
%h4 Config:
|
33
|
+
%ul
|
34
|
+
- if hook["config"][:secret].present?
|
35
|
+
%li
|
36
|
+
%strong secret:
|
37
|
+
= hook["config"][:secret]
|
38
|
+
%li
|
39
|
+
%strong url:
|
40
|
+
= hook["config"][:url]
|
41
|
+
%li
|
42
|
+
%strong content type:
|
43
|
+
= hook["config"][:content_type]
|
44
|
+
%li
|
45
|
+
%strong ssl:
|
46
|
+
= hook["config"][:insecure_ssl]
|
47
|
+
|
48
|
+
%h4 Test url:
|
49
|
+
%p
|
50
|
+
= hook["test_url"]
|
51
|
+
|
52
|
+
%h4 Last response:
|
53
|
+
%p
|
54
|
+
= hook["last_response"].to_json
|
55
|
+
|
56
|
+
|
57
|
+
.col-sm-12
|
58
|
+
%h3
|
59
|
+
= hook.present? ? "Will update exiting (#{hook["id"]}) hook." : "Will create new hook."
|
60
|
+
%form{:action => "/repos/#{repo.name}/add_hook", method: "post"}
|
61
|
+
%input{:type => "text", name: "webhook_url", placeholder: "type the receive hook url...", style:"width:250px"}
|
62
|
+
%button Send
|
63
|
+
|
64
|
+
%p.small
|
65
|
+
we are going to send the hook to
|
66
|
+
%strong
|
67
|
+
=repo.url
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
.pull-right
|
4
|
+
%br
|
5
|
+
%a.btn.btn.btn-success{href: "/repos/sync"}
|
6
|
+
%span.glyphicon.glyphicon-refresh
|
7
|
+
SYNC
|
8
|
+
|
9
|
+
-#
|
10
|
+
- repos.each do |repo|
|
11
|
+
%ul.list-group
|
12
|
+
%li.list-group-item
|
13
|
+
|
14
|
+
.pull-right
|
15
|
+
%a.btn{href: "/repos/add/#{repo.gb_id}"}
|
16
|
+
ADD REPO
|
17
|
+
%span.btn.glyphicon.glyphicon-plus-sign
|
18
|
+
|
19
|
+
.row
|
20
|
+
%span.col-sm-1
|
21
|
+
%a{src: repo.github_data["owner"]["url"] }
|
22
|
+
%img{ src: repo.github_data["owner"]["avatar_url"], width: 66 }
|
23
|
+
%span.col-sm-8
|
24
|
+
%h4= repo.name
|
25
|
+
%a{href: repo.url}
|
26
|
+
view on github
|
27
|
+
%p
|
28
|
+
.clearfix
|
29
|
+
.well
|
30
|
+
%p= repo.github_data["description"]
|
31
|
+
-#
|
32
|
+
%p
|
33
|
+
clone url:
|
34
|
+
= repo.github_data["clone_url"]
|
35
|
+
|
36
|
+
%span
|
37
|
+
= repo.github_data["fork"]
|
38
|
+
= repo.github_data["private"]
|
39
|
+
|
40
|
+
- if repos.any?
|
41
|
+
%h2 Repositories:
|
42
|
+
|
43
|
+
.panel.panel-default
|
44
|
+
.panel-heading
|
45
|
+
Github Repos
|
46
|
+
|
47
|
+
|
48
|
+
- repos.each do |repo|
|
49
|
+
%ul.list-group
|
50
|
+
%li.list-group-item
|
51
|
+
|
52
|
+
.pull-right
|
53
|
+
%a.btn{href: "/repos/add/#{repo['id']}"}
|
54
|
+
ADD REPO
|
55
|
+
%span.btn.glyphicon.glyphicon-plus-sign
|
56
|
+
|
57
|
+
.row
|
58
|
+
%span.col-sm-2
|
59
|
+
%a{src: repo["owner"]["url"] }
|
60
|
+
%img{ src: repo["owner"]["avatar_url"], width: 120 }
|
61
|
+
%span.col-sm-7
|
62
|
+
.pull-right
|
63
|
+
|
64
|
+
- if repo["fork"]
|
65
|
+
%i.fa.fa-code-fork{title: "is a fork"}
|
66
|
+
|
67
|
+
- if repo["private"]
|
68
|
+
%i.fa.fa-lock{title: "is private"}
|
69
|
+
|
70
|
+
%h4= repo.name
|
71
|
+
%a{href: repo['html_url'], target: :blank}
|
72
|
+
View on github
|
73
|
+
%i.fa.fa-external-link
|
74
|
+
%p.small= repo["description"]
|
75
|
+
|
76
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#repo-menu.pull-right
|
2
|
+
%ul.nav.nav-pills{:role => "tablist"}
|
3
|
+
|
4
|
+
- unless build.blank?
|
5
|
+
%li
|
6
|
+
%a.btn.refresh{href:"/repos/#{repo.name}/builds/#{build['_id']}/restart", title: "Restart Build"}
|
7
|
+
%i.fa.fa-refresh{class: "#{'fa-refresh'}"}
|
8
|
+
|
9
|
+
%li{class: "#{'active' if active == 'current'}"}
|
10
|
+
%a{:href => "/repos/#{repo.name}"} Current
|
11
|
+
%li{class: "#{'active' if active == 'builds'}"}
|
12
|
+
%a{:href => "/repos/#{repo.name}/builds"} Build history
|
13
|
+
%li{class: "#{'active' if active == 'config'}"}
|
14
|
+
%a{:href => "/repos/#{repo.name}/config"} Config Hook
|
15
|
+
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
%div{id: "repo-#{repo.id}" }
|
3
|
+
|
4
|
+
= haml :"repos/menu" , locals:{ repo: repo, active: "current", build: build}
|
5
|
+
|
6
|
+
.title
|
7
|
+
%h2
|
8
|
+
%span#repo-name= repo.name
|
9
|
+
= haml :"repos/spinner", locals: {repo: repo}
|
10
|
+
|
11
|
+
%h5
|
12
|
+
%strong= repo.url
|
13
|
+
|
14
|
+
- if build.present?
|
15
|
+
.panel.panel-default
|
16
|
+
.panel-heading
|
17
|
+
Current Build
|
18
|
+
|
19
|
+
.panel-body
|
20
|
+
|
21
|
+
.col-sm-8
|
22
|
+
%strong= build.commit.branch
|
23
|
+
\-
|
24
|
+
= build.commit.message
|
25
|
+
|
26
|
+
.pull-right
|
27
|
+
= status_label(build.status)
|
28
|
+
%p
|
29
|
+
%abbr.timeago{title:build.build_time}
|
30
|
+
%br
|
31
|
+
duration:
|
32
|
+
%strong= build.duration.to_i.round(2)
|
33
|
+
|
34
|
+
|
35
|
+
.col-sm-12
|
36
|
+
%img.avatar{ src: avatar_url(build.commit.email, 35) }
|
37
|
+
%strong= build.commit.author
|
38
|
+
= build.commit.email
|
39
|
+
|
40
|
+
.pull-right
|
41
|
+
%a{href: commit_url(repo, build.sha), target: :blank}
|
42
|
+
%img{src: "/assets/github.svg", width:"20px"}
|
43
|
+
= "commit ... #{build["sha"][0..6]}"
|
44
|
+
%strong
|
45
|
+
%abbr.timeago{title:build.commit.created_at}
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
%ul.list-group
|
50
|
+
%li.list-group-item.build-item
|
51
|
+
|
52
|
+
.build-response
|
53
|
+
%p
|
54
|
+
%pre#log.ansi= build.response
|
55
|
+
- else
|
56
|
+
.alert.alert-warning
|
57
|
+
No builds yet.
|
58
|
+
|
59
|
+
%a{:href => "/repos/#{repo.name}/run_commit"}
|
60
|
+
Run last commit in master branch
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module Perkins
|
5
|
+
class Worker
|
6
|
+
|
7
|
+
#include Celluloid
|
8
|
+
|
9
|
+
def self.perform(repo, sha, branch)
|
10
|
+
repo.load_git
|
11
|
+
|
12
|
+
return if repo.runner.blank?
|
13
|
+
|
14
|
+
repo.runner.sha = sha
|
15
|
+
repo.runner.branch = branch
|
16
|
+
|
17
|
+
send_sse({repo: {id: repo.id, name: repo.name , status: "start"} })
|
18
|
+
|
19
|
+
repo.runner.run(sha)
|
20
|
+
|
21
|
+
report = repo.build_reports.find_by(sha: sha)
|
22
|
+
send_sse({repo: {id: repo.id, name: repo.name , status: "stop", report: report } })
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.send_sse(msg)
|
26
|
+
postData = Net::HTTP.post_form(
|
27
|
+
URI.parse('http://localhost:3000/sse'),
|
28
|
+
{'msg'=> msg.to_json }
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/perkins.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#require "perkins/version"
|
2
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require "logger"
|
5
|
+
require 'active_support/core_ext'
|
6
|
+
require 'redis'
|
7
|
+
require 'redis-namespace'
|
8
|
+
require "travis/yaml"
|
9
|
+
require "active_record"
|
10
|
+
|
11
|
+
require 'dotenv'
|
12
|
+
Dotenv.load
|
13
|
+
require 'octokit'
|
14
|
+
Octokit.auto_paginate = true
|
15
|
+
#require 'core_ext/hash/deep_symbolize_keys'
|
16
|
+
|
17
|
+
module Perkins
|
18
|
+
autoload :VERSION, 'perkins/version.rb'
|
19
|
+
autoload :Repo, 'perkins/repo.rb'
|
20
|
+
autoload :BuildReport, 'perkins/build_report.rb'
|
21
|
+
autoload :Runner, 'perkins/runner.rb'
|
22
|
+
autoload :Build, 'perkins/build.rb'
|
23
|
+
autoload :Commit, 'perkins/commit.rb'
|
24
|
+
autoload :Server, 'perkins/server.rb'
|
25
|
+
autoload :Worker, 'perkins/worker.rb'
|
26
|
+
autoload :Listener, 'perkins/listener.rb'
|
27
|
+
autoload :ThorUtils, 'perkins/thor_utils.rb'
|
28
|
+
autoload :Logger, 'perkins/logger.rb'
|
29
|
+
autoload :Application, 'perkins/application.rb'
|
30
|
+
autoload :AppProxy, 'perkins/dsl/app_proxy.rb'
|
31
|
+
autoload :CLI, 'perkins/cli.rb'
|
32
|
+
ROOT_PATH = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'perkins/dsl'
|
36
|
+
|
data/perkins.gemspec
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'perkins/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "perkins"
|
8
|
+
spec.version = Perkins::VERSION
|
9
|
+
spec.authors = ["miguel michelson"]
|
10
|
+
spec.email = ["miguelmichelson@gmail.com"]
|
11
|
+
spec.summary = "Thin CI"
|
12
|
+
spec.description = "Minimal CI"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'activesupport', ['>= 3', '< 4.1']
|
22
|
+
spec.add_dependency 'activerecord', ['>= 3', '< 4.1']
|
23
|
+
|
24
|
+
spec.add_dependency "sinatra-activerecord"
|
25
|
+
spec.add_dependency "sinatra-contrib"
|
26
|
+
spec.add_dependency "sqlite3"
|
27
|
+
|
28
|
+
spec.add_runtime_dependency("git")
|
29
|
+
spec.add_runtime_dependency("celluloid")
|
30
|
+
spec.add_runtime_dependency("celluloid-io")
|
31
|
+
spec.add_runtime_dependency("redis")
|
32
|
+
spec.add_runtime_dependency("thor")
|
33
|
+
spec.add_runtime_dependency("sinatra")
|
34
|
+
spec.add_runtime_dependency("haml")
|
35
|
+
spec.add_runtime_dependency("sprockets")
|
36
|
+
spec.add_runtime_dependency("yui-compressor")
|
37
|
+
spec.add_runtime_dependency("rdiscount")
|
38
|
+
spec.add_runtime_dependency("travis-yaml")
|
39
|
+
spec.add_runtime_dependency("redis-namespace")
|
40
|
+
spec.add_runtime_dependency("thin")
|
41
|
+
|
42
|
+
spec.add_dependency "warden-github", "~>1.0"
|
43
|
+
|
44
|
+
# I find it well worth to include CoffeeScript and SASS as well
|
45
|
+
spec.add_runtime_dependency( "coffee-script")
|
46
|
+
spec.add_runtime_dependency( "sass")
|
47
|
+
|
48
|
+
|
49
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
50
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
51
|
+
spec.add_development_dependency "fakeredis"
|
52
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
2
|
+
|
3
|
+
describe "Repo" do
|
4
|
+
|
5
|
+
let(:user_api) {
|
6
|
+
Octokit::Client.new(
|
7
|
+
login: ENV['LOGIN'],
|
8
|
+
access_token: ENV['ACCESS_TOKEN']
|
9
|
+
)
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:file){
|
13
|
+
f = File.expand_path(File.dirname(__FILE__) + '/../../fixtures/.travis.yml')
|
14
|
+
Travis::Yaml.parse( File.open(f).read )
|
15
|
+
}
|
16
|
+
|
17
|
+
let(:github_user){
|
18
|
+
Warden::GitHub::User.new
|
19
|
+
}
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
perkins_app
|
23
|
+
allow_any_instance_of(Warden::GitHub::User).to receive(:api).and_return(user_api)
|
24
|
+
@user = Warden::GitHub::User.new
|
25
|
+
Perkins::Repo.sync_github_repos(@user)
|
26
|
+
|
27
|
+
to_add = Perkins::Repo.synced_records.where(name: "michelson/lazy_high_charts").first
|
28
|
+
r = Perkins::Repo.add_from_github(to_add.gb_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "runner config" do
|
32
|
+
before :each do
|
33
|
+
@repo = Perkins::Repo.where(cached: false).last
|
34
|
+
allow_any_instance_of(Perkins::Repo).to receive(:check_config_existence).and_return(file)
|
35
|
+
@repo.load_git
|
36
|
+
expect(@repo.git).to be_instance_of(Git::Base)
|
37
|
+
@path = @repo.git.dir.path
|
38
|
+
end
|
39
|
+
|
40
|
+
after :each do
|
41
|
+
Perkins::Repo.delete_all
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have a runner" do
|
45
|
+
expect(@repo.runner).to be_instance_of(Perkins::Runner)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "run run run should add a new report" do
|
49
|
+
sha = @repo.git.log.map(&:sha).first
|
50
|
+
@repo.runner.run(sha)
|
51
|
+
expect(@repo.build_reports.size).to be == 1
|
52
|
+
#binding.pry
|
53
|
+
#expect(@repo.runner.status).to be == true
|
54
|
+
#expect(@repo.runner.response).to_not be_blank
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|