magi 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +12 -3
- data/Procfile +4 -0
- data/README.md +25 -1
- data/app/assets/stylesheets/application.css +1 -0
- data/app/assets/stylesheets/builds.scss +35 -0
- data/app/assets/stylesheets/common.scss +69 -0
- data/app/assets/stylesheets/jobs.scss +121 -0
- data/app/assets/stylesheets/layout.scss +19 -0
- data/app/assets/stylesheets/mixin.scss +6 -0
- data/app/controllers/application_controller.rb +16 -0
- data/app/controllers/builds_controller.rb +45 -0
- data/app/controllers/jobs_controller.rb +43 -0
- data/app/models/build.rb +39 -0
- data/app/models/job.rb +88 -0
- data/app/views/builds/show.html.slim +36 -0
- data/app/views/jobs/_form.html.slim +27 -0
- data/app/views/jobs/edit.html.slim +9 -0
- data/app/views/jobs/index.html.slim +19 -0
- data/app/views/jobs/new.html.slim +7 -0
- data/app/views/jobs/show.html.slim +24 -0
- data/app/views/layouts/application.html.slim +10 -0
- data/app/workers/build_worker.rb +8 -0
- data/bin/magi +6 -0
- data/config/application.rb +1 -1
- data/config/database.yml +21 -17
- data/config/routes.rb +4 -55
- data/db/migrate/20130531143239_create_jobs.rb +10 -0
- data/db/migrate/20130531155155_create_builds.rb +14 -0
- data/db/schema.rb +35 -0
- data/lib/magi/command.rb +53 -0
- data/lib/magi/executer.rb +31 -0
- data/lib/magi/scheduler.rb +55 -0
- data/lib/magi/version.rb +1 -1
- data/lib/magi.rb +1 -4
- data/magi.gemspec +29 -1
- data/script/clock.rb +5 -0
- data/spec/factories/build.rb +6 -0
- data/spec/factories/job.rb +7 -0
- data/spec/models/build_spec.rb +35 -0
- data/spec/models/job_spec.rb +54 -0
- data/spec/requests/builds_spec.rb +68 -0
- data/spec/requests/jobs_spec.rb +93 -0
- data/spec/spec_helper.rb +28 -0
- metadata +324 -50
- data/.gitignore +0 -19
- data/app/mailers/.gitkeep +0 -0
- data/app/models/.gitkeep +0 -0
- data/app/views/layouts/application.html.erb +0 -14
- data/doc/README_FOR_APP +0 -2
- data/lib/assets/.gitkeep +0 -0
- data/lib/tasks/.gitkeep +0 -0
- data/log/.gitkeep +0 -0
- data/public/index.html +0 -241
- data/test/fixtures/.gitkeep +0 -0
- data/test/functional/.gitkeep +0 -0
- data/test/integration/.gitkeep +0 -0
- data/test/performance/browsing_test.rb +0 -12
- data/test/test_helper.rb +0 -13
- data/test/unit/.gitkeep +0 -0
- data/vendor/assets/javascripts/.gitkeep +0 -0
- data/vendor/assets/stylesheets/.gitkeep +0 -0
- data/vendor/plugins/.gitkeep +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 912ef942160db8fe16a33b901a9213a40dc8482e
|
4
|
+
data.tar.gz: 5a3f6069f1c918788815dde909a74469a3a3e047
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b768a1e1a60ffcd0dcf7b8c7f78ffa004e5ffc4c64b395bc852a18ae964f638fe3520dd4331604dd80fda472de21b5c80ddf4b70506c1c88106c03f49a118a0
|
7
|
+
data.tar.gz: cedf3fd66a1b876a3f64a34dee6effe1ab0659b29603888508ab8a5ae2c0681ec2e4352c677fd14a1c54af95f3985f1b765f104e96147d39eba3c08355a0532a
|
data/Gemfile
CHANGED
@@ -1,19 +1,28 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem "font-awesome-rails"
|
5
6
|
gem "jquery-rails"
|
7
|
+
gem "quiet_assets"
|
8
|
+
gem "sidekiq"
|
9
|
+
gem "slim"
|
6
10
|
|
7
11
|
group :development, :test do
|
8
12
|
gem "pry-rails"
|
9
13
|
end
|
10
14
|
|
11
15
|
group :test do
|
16
|
+
gem "factory_girl_rails"
|
17
|
+
gem "response_code_matchers"
|
18
|
+
gem "rspec-json_matcher"
|
12
19
|
gem "rspec-rails"
|
20
|
+
gem "simplecov"
|
21
|
+
gem "thin"
|
13
22
|
end
|
14
23
|
|
15
24
|
group :assets do
|
16
|
-
gem "sass-rails",
|
25
|
+
gem "sass-rails", "~> 3.2.3"
|
17
26
|
gem "coffee-rails", "~> 3.2.1"
|
18
27
|
gem "uglifier", ">= 1.0.3"
|
19
28
|
end
|
data/Procfile
ADDED
data/README.md
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
# Magi
|
2
|
+
A continuous integration server implementation.
|
2
3
|
|
3
|
-
|
4
|
+

|
5
|
+
|
6
|
+
## Install
|
4
7
|
```
|
5
8
|
$ gem install magi
|
9
|
+
$ brew install mysql redis # or other commands to install MySQL and Redis
|
10
|
+
```
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
```
|
14
|
+
$ magi setup
|
15
|
+
$ magi start # open http://localhost:3000
|
6
16
|
```
|
17
|
+
|
18
|
+
## Hack
|
19
|
+
Magi is just a rails application.
|
20
|
+
Feel free to do what you want.
|
21
|
+
|
22
|
+
### tools
|
23
|
+
* Rails: HTTP server
|
24
|
+
* Sidekiq: background worker
|
25
|
+
* Redis: worker queue
|
26
|
+
* MySQL: store jobs & builds
|
27
|
+
|
28
|
+
### todo
|
29
|
+
* plugin system
|
30
|
+
* cli options (e.g. http port, rails env, redis conf)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
@import "mixin";
|
2
|
+
|
3
|
+
section.build {
|
4
|
+
&.success h1 {
|
5
|
+
color: #27AE60;
|
6
|
+
}
|
7
|
+
|
8
|
+
&.failure h1 {
|
9
|
+
color: #C0392B;
|
10
|
+
}
|
11
|
+
|
12
|
+
&.success h1 span:before {
|
13
|
+
content: "\F058";
|
14
|
+
}
|
15
|
+
|
16
|
+
&.build.failure h1 span:before {
|
17
|
+
content: "\F057";
|
18
|
+
}
|
19
|
+
|
20
|
+
&.build.unfinished h1 span:before {
|
21
|
+
content: "\F056";
|
22
|
+
}
|
23
|
+
|
24
|
+
td {
|
25
|
+
padding-right: 1em;
|
26
|
+
}
|
27
|
+
|
28
|
+
pre {
|
29
|
+
@include box;
|
30
|
+
margin-top: 1em;
|
31
|
+
padding: .5em 1em;
|
32
|
+
background: #eee;
|
33
|
+
overflow-x: scroll;
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
@import "mixin";
|
2
|
+
|
3
|
+
* {
|
4
|
+
margin: 0;
|
5
|
+
padding: 0;
|
6
|
+
}
|
7
|
+
|
8
|
+
body {
|
9
|
+
color: #333;
|
10
|
+
font-family: "Helvetica Neue", "Calibri", sans-serif;
|
11
|
+
line-height: 1.7;
|
12
|
+
}
|
13
|
+
|
14
|
+
a {
|
15
|
+
color: inherit;
|
16
|
+
text-decoration: none;
|
17
|
+
}
|
18
|
+
|
19
|
+
i {
|
20
|
+
margin-right: .3em;
|
21
|
+
}
|
22
|
+
|
23
|
+
textarea,
|
24
|
+
input {
|
25
|
+
font-size: 1em;
|
26
|
+
}
|
27
|
+
|
28
|
+
textarea,
|
29
|
+
input[type="text"] {
|
30
|
+
@include box;
|
31
|
+
width: 100%;
|
32
|
+
}
|
33
|
+
|
34
|
+
*:before {
|
35
|
+
margin-right: .3em;
|
36
|
+
font-family: FontAwesome;
|
37
|
+
}
|
38
|
+
|
39
|
+
.button {
|
40
|
+
@include box;
|
41
|
+
width: 10em;
|
42
|
+
font-size: 1em;
|
43
|
+
color: white;
|
44
|
+
background: #F39C12;
|
45
|
+
border-color: #F39C12;
|
46
|
+
line-height: inherit;
|
47
|
+
cursor: pointer;
|
48
|
+
text-align: center;
|
49
|
+
}
|
50
|
+
|
51
|
+
section.breadcrumbs {
|
52
|
+
ul {
|
53
|
+
@include box;
|
54
|
+
border-color: #eee;
|
55
|
+
background: #eee;
|
56
|
+
list-style: none;
|
57
|
+
overflow: hidden;
|
58
|
+
color: #888;
|
59
|
+
}
|
60
|
+
|
61
|
+
li {
|
62
|
+
float: left;
|
63
|
+
margin-right: 1em;
|
64
|
+
}
|
65
|
+
|
66
|
+
li.delimiter:before {
|
67
|
+
content: "\F105";
|
68
|
+
}
|
69
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
@import "mixin";
|
2
|
+
|
3
|
+
section.jobs {
|
4
|
+
h1:before {
|
5
|
+
content: "\F13D";
|
6
|
+
}
|
7
|
+
|
8
|
+
p {
|
9
|
+
color: #ccc;
|
10
|
+
}
|
11
|
+
|
12
|
+
ul {
|
13
|
+
margin-top: 1em;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
section.job_settings {
|
18
|
+
h1:before {
|
19
|
+
content: "\F085";
|
20
|
+
}
|
21
|
+
|
22
|
+
td {
|
23
|
+
padding-right: 1em;
|
24
|
+
}
|
25
|
+
|
26
|
+
input[type="submit"] {
|
27
|
+
margin-top: 1em;
|
28
|
+
background: #34495e;
|
29
|
+
border-color: #34495e;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
section.jobs,
|
34
|
+
section.builds {
|
35
|
+
.buttons {
|
36
|
+
overflow: hidden;
|
37
|
+
}
|
38
|
+
|
39
|
+
.buttons a {
|
40
|
+
float: left;
|
41
|
+
display: block;
|
42
|
+
margin-right: 1em;
|
43
|
+
}
|
44
|
+
|
45
|
+
.buttons a.new:before {
|
46
|
+
content: "\F040";
|
47
|
+
}
|
48
|
+
|
49
|
+
.buttons a.run:before {
|
50
|
+
content: "\F04B";
|
51
|
+
}
|
52
|
+
|
53
|
+
.buttons a.new,
|
54
|
+
.buttons a.settings {
|
55
|
+
background: #2C3E50;
|
56
|
+
border-color: #2C3E50;
|
57
|
+
}
|
58
|
+
|
59
|
+
.buttons a.settings:before {
|
60
|
+
content: "\F013";
|
61
|
+
}
|
62
|
+
|
63
|
+
.buttons a.delete {
|
64
|
+
background: #C0392B;
|
65
|
+
border-color: #C0392B;
|
66
|
+
}
|
67
|
+
|
68
|
+
.buttons a.delete:before {
|
69
|
+
content: "\F014";
|
70
|
+
}
|
71
|
+
|
72
|
+
.button {
|
73
|
+
margin-top: .5em;
|
74
|
+
}
|
75
|
+
|
76
|
+
ul {
|
77
|
+
margin-top: 1em;
|
78
|
+
list-style: none;
|
79
|
+
}
|
80
|
+
|
81
|
+
li a {
|
82
|
+
@include box;
|
83
|
+
display: block;
|
84
|
+
}
|
85
|
+
|
86
|
+
li a:hover {
|
87
|
+
background: #fafafa;
|
88
|
+
}
|
89
|
+
|
90
|
+
li.unfinished a:before {
|
91
|
+
content: "\F056";
|
92
|
+
}
|
93
|
+
|
94
|
+
li.success a:before {
|
95
|
+
content: "\F058";
|
96
|
+
color: #27AE60;
|
97
|
+
}
|
98
|
+
|
99
|
+
li.failure a:before {
|
100
|
+
content: "\F057";
|
101
|
+
color: #C0392B;
|
102
|
+
}
|
103
|
+
|
104
|
+
li.success a {
|
105
|
+
border-color: #27AE60;
|
106
|
+
}
|
107
|
+
|
108
|
+
li.failure a {
|
109
|
+
border-color: #C0392B;
|
110
|
+
}
|
111
|
+
|
112
|
+
li span {
|
113
|
+
margin-right: 1em;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
section.builds {
|
118
|
+
h1:before {
|
119
|
+
content: "\F0FB";
|
120
|
+
}
|
121
|
+
}
|
@@ -1,3 +1,19 @@
|
|
1
1
|
class ApplicationController < ActionController::Base
|
2
2
|
protect_from_forgery
|
3
|
+
|
4
|
+
respond_to :html, :json
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def require_resource_params
|
9
|
+
head 400 unless resource_params
|
10
|
+
end
|
11
|
+
|
12
|
+
def resource_name
|
13
|
+
self.class.name.split("::").last.sub(/Controller$/, "").singularize.underscore
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_params
|
17
|
+
params[resource_name]
|
18
|
+
end
|
3
19
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class BuildsController < ApplicationController
|
2
|
+
before_filter :require_job
|
3
|
+
before_filter :require_resources, only: :index
|
4
|
+
before_filter :require_resource, only: [:show, :update, :destroy]
|
5
|
+
before_filter :require_resource_params, only: :update
|
6
|
+
|
7
|
+
def index
|
8
|
+
respond_with @resources
|
9
|
+
end
|
10
|
+
|
11
|
+
def show
|
12
|
+
respond_with @resource
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
resource = @job.queue
|
17
|
+
respond_with resource, location: [@job, resource]
|
18
|
+
end
|
19
|
+
|
20
|
+
def update
|
21
|
+
respond_with @resource.update_attributes(resource_params.slice(:status))
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
respond_with @resource.destroy
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def require_job
|
31
|
+
@job = Job.find(params[:job_id])
|
32
|
+
end
|
33
|
+
|
34
|
+
def scope
|
35
|
+
@job.builds
|
36
|
+
end
|
37
|
+
|
38
|
+
def require_resources
|
39
|
+
@resources = scope
|
40
|
+
end
|
41
|
+
|
42
|
+
def require_resource
|
43
|
+
@resource = scope.find(params[:id])
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class JobsController < ApplicationController
|
2
|
+
before_filter :require_resource_params, only: [:create, :update]
|
3
|
+
before_filter :require_resources, only: :index
|
4
|
+
before_filter :require_resource, only: [:show, :edit, :update, :destroy]
|
5
|
+
|
6
|
+
def index
|
7
|
+
respond_with @resources
|
8
|
+
end
|
9
|
+
|
10
|
+
def show
|
11
|
+
respond_with @resource
|
12
|
+
end
|
13
|
+
|
14
|
+
def new
|
15
|
+
respond_with @resource = scope.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
respond_with @resource = scope.create_with_properties(resource_params)
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
respond_with @resource.update_attributes_with_properties(resource_params)
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy
|
27
|
+
respond_with @resource.destroy
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def scope
|
33
|
+
Job.scoped
|
34
|
+
end
|
35
|
+
|
36
|
+
def require_resources
|
37
|
+
@resources = scope
|
38
|
+
end
|
39
|
+
|
40
|
+
def require_resource
|
41
|
+
@resource = scope.find(params[:id])
|
42
|
+
end
|
43
|
+
end
|
data/app/models/build.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class Build < ActiveRecord::Base
|
2
|
+
attr_accessible :finished_at, :started_at, :output, :status
|
3
|
+
|
4
|
+
validates :job_id, presence: true
|
5
|
+
|
6
|
+
belongs_to :job, touch: true
|
7
|
+
|
8
|
+
scope :recent, -> { order("created_at DESC") }
|
9
|
+
|
10
|
+
scope :finished, -> { where("finished_at IS NOT NULL") }
|
11
|
+
|
12
|
+
# Pushes this build to worker's queue.
|
13
|
+
def queue
|
14
|
+
BuildWorker.perform_async(id)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Runs this build, usually called from BuildWorker#perform.
|
18
|
+
def start
|
19
|
+
update_attributes!(started_at: Time.now)
|
20
|
+
result = job.start
|
21
|
+
update_attributes!(finished_at: Time.now, status: result[:status], output: result[:output])
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns elapsed sec as a Float or nil.
|
25
|
+
def sec
|
26
|
+
finished_at - started_at if finished_at && started_at
|
27
|
+
end
|
28
|
+
|
29
|
+
def status_name
|
30
|
+
case status
|
31
|
+
when true
|
32
|
+
"success"
|
33
|
+
when false
|
34
|
+
"failure"
|
35
|
+
when nil
|
36
|
+
"unfinished"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/app/models/job.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
class Job < ActiveRecord::Base
|
2
|
+
attr_accessible :name, :config
|
3
|
+
|
4
|
+
serialize :config, Hash
|
5
|
+
|
6
|
+
validates :name, presence: true
|
7
|
+
|
8
|
+
has_many :builds
|
9
|
+
|
10
|
+
scope :recent, -> { order("updated_at DESC") }
|
11
|
+
|
12
|
+
delegate :status, :status_name, :status_icon_css_class, to: :last_finished_build, allow_nil: true
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def create_with_properties(properties)
|
16
|
+
job = new
|
17
|
+
properties.each {|key, value| job.send("#{key}=", value) }
|
18
|
+
job.tap(&:save)
|
19
|
+
end
|
20
|
+
|
21
|
+
def queue
|
22
|
+
select(&:scheduled?).each(&:queue)
|
23
|
+
end
|
24
|
+
|
25
|
+
def property(name)
|
26
|
+
properties << name
|
27
|
+
|
28
|
+
define_method(name) do
|
29
|
+
config[name.to_s]
|
30
|
+
end
|
31
|
+
|
32
|
+
define_method("#{name}=") do |value|
|
33
|
+
config[name.to_s] = value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def properties
|
38
|
+
@properties ||= []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
property(:description)
|
43
|
+
|
44
|
+
property(:schedule)
|
45
|
+
|
46
|
+
property(:script)
|
47
|
+
|
48
|
+
def start
|
49
|
+
script ? execute : raise_script_not_found
|
50
|
+
end
|
51
|
+
|
52
|
+
def scheduler
|
53
|
+
Magi::Scheduler.new(schedule)
|
54
|
+
end
|
55
|
+
|
56
|
+
def scheduled?
|
57
|
+
schedule && scheduler.scheduled?
|
58
|
+
end
|
59
|
+
|
60
|
+
def queue
|
61
|
+
builds.create.tap(&:queue)
|
62
|
+
end
|
63
|
+
|
64
|
+
def status_name
|
65
|
+
last_finished_build.try(:status_name) || "unfinished"
|
66
|
+
end
|
67
|
+
|
68
|
+
def last_finished_build
|
69
|
+
builds.finished.order(:finished_at).last
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_attributes_with_properties(properties)
|
73
|
+
properties.each {|key, value| send("#{key}=", value) }
|
74
|
+
tap(&:save)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def execute
|
80
|
+
Magi::Executer.execute(script)
|
81
|
+
end
|
82
|
+
|
83
|
+
def raise_script_not_found
|
84
|
+
raise ScriptNotFound, 'You must set script["config"]'
|
85
|
+
end
|
86
|
+
|
87
|
+
class ScriptNotFound < StandardError; end
|
88
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
section.breadcrumbs
|
2
|
+
ul
|
3
|
+
li= link_to "Home", jobs_path
|
4
|
+
li.delimiter
|
5
|
+
li= link_to @resource.job.name, @resource.job
|
6
|
+
li.delimiter
|
7
|
+
li= link_to "##{@resource.id}", [@resource.job, @resource]
|
8
|
+
|
9
|
+
section.build class = @resource.status_name
|
10
|
+
h1
|
11
|
+
span ##{@resource.id}
|
12
|
+
|
13
|
+
table
|
14
|
+
tr
|
15
|
+
td started_at
|
16
|
+
td= ":"
|
17
|
+
td= @resource.started_at
|
18
|
+
|
19
|
+
tr
|
20
|
+
td finished_at
|
21
|
+
td= ":"
|
22
|
+
td= @resource.finished_at
|
23
|
+
|
24
|
+
tr
|
25
|
+
td sec
|
26
|
+
td= ":"
|
27
|
+
td= @resource.sec
|
28
|
+
|
29
|
+
tr
|
30
|
+
td status
|
31
|
+
td= ":"
|
32
|
+
td= @resource.status_name
|
33
|
+
|
34
|
+
pre
|
35
|
+
code
|
36
|
+
= @resource.output
|
@@ -0,0 +1,27 @@
|
|
1
|
+
section.job_settings
|
2
|
+
h1 Settings
|
3
|
+
|
4
|
+
= form_for resource do |f|
|
5
|
+
.field
|
6
|
+
p= f.label :name
|
7
|
+
p= f.text_field :name, placeholder: "required"
|
8
|
+
|
9
|
+
.field
|
10
|
+
p= f.label :description
|
11
|
+
p= f.text_area :description, rows: 3
|
12
|
+
|
13
|
+
.field
|
14
|
+
p= f.label :script
|
15
|
+
p= f.text_area :script, rows: 6
|
16
|
+
|
17
|
+
.field
|
18
|
+
p= f.label :schedule
|
19
|
+
p= f.text_field :schedule, placeholder: "* * * * *"
|
20
|
+
|
21
|
+
- (resource.class.properties - [:description, :schedule, :script]).each do |name|
|
22
|
+
.field
|
23
|
+
p= f.label name
|
24
|
+
p= f.text_field name
|
25
|
+
|
26
|
+
.field
|
27
|
+
p= f.submit class: "button"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
section.breadcrumbs
|
2
|
+
ul
|
3
|
+
li= link_to "Home", jobs_path
|
4
|
+
|
5
|
+
section.jobs
|
6
|
+
h1 JOBS
|
7
|
+
|
8
|
+
p #{Job.count} jobs are found.
|
9
|
+
|
10
|
+
|
11
|
+
.buttons
|
12
|
+
= link_to "New", [:new, :job], class: "button new"
|
13
|
+
|
14
|
+
ul
|
15
|
+
- @resources.recent.each do |resource|
|
16
|
+
li class = resource.status_name
|
17
|
+
= link_to resource do
|
18
|
+
span
|
19
|
+
= resource.name
|
@@ -0,0 +1,24 @@
|
|
1
|
+
section.breadcrumbs
|
2
|
+
ul
|
3
|
+
li= link_to "Home", jobs_path
|
4
|
+
li.delimiter
|
5
|
+
li= link_to @resource.name, @resource
|
6
|
+
|
7
|
+
section.builds
|
8
|
+
h1
|
9
|
+
= @resource.name
|
10
|
+
|
11
|
+
p
|
12
|
+
= @resource.description || "(no description)"
|
13
|
+
|
14
|
+
.buttons
|
15
|
+
= link_to "Run", [@resource, :builds], method: "POST", class: "button run"
|
16
|
+
= link_to "Settings", [:edit, @resource], class: "button settings"
|
17
|
+
= link_to "Delete", @resource, method: "DELETE", confirm: "Are you sure?", class: "button delete"
|
18
|
+
|
19
|
+
ul
|
20
|
+
- @resource.builds.recent.limit(10).each do |build|
|
21
|
+
li class = build.status_name
|
22
|
+
= link_to [@resource, build] do
|
23
|
+
span.id ##{build.id}
|
24
|
+
span= build.finished_at
|