konstant 0.0.8
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/.gitignore +17 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +7 -0
- data/bin/konstant +87 -0
- data/data/templates/data_dir/konstant.js +16 -0
- data/data/templates/data_dir/projects/.gitkeep +0 -0
- data/data/templates/project/build +8 -0
- data/data/templates/project/cleanup +5 -0
- data/data/templates/project/deploy +4 -0
- data/data/templates/project/run.txt +0 -0
- data/konstant.gemspec +29 -0
- data/lib/konstant/build.rb +86 -0
- data/lib/konstant/builder.rb +108 -0
- data/lib/konstant/cli.rb +37 -0
- data/lib/konstant/project.rb +75 -0
- data/lib/konstant/runner.rb +50 -0
- data/lib/konstant/scheduler.rb +50 -0
- data/lib/konstant/version.rb +3 -0
- data/lib/konstant/web.rb +39 -0
- data/lib/konstant.rb +81 -0
- data/public/assets/angular.min.js +216 -0
- data/public/assets/app.js +60 -0
- data/public/assets/bootstrap-theme.min.css +5 -0
- data/public/assets/bootstrap.min.css +5 -0
- data/public/assets/bootstrap.min.js +6 -0
- data/public/assets/glyphicons-halflings-regular.eot +0 -0
- data/public/assets/glyphicons-halflings-regular.svg +229 -0
- data/public/assets/glyphicons-halflings-regular.ttf +0 -0
- data/public/assets/glyphicons-halflings-regular.woff +0 -0
- data/public/assets/jquery-2.1.1.min.js +4 -0
- data/public/assets/style.css +3 -0
- data/public/index.html +175 -0
- data/spec/file_spec.rb +28 -0
- data/spec/fixtures/projects/test_project_01/build +6 -0
- data/spec/fixtures/projects/test_project_02/build +3 -0
- data/spec/konstant/builder_spec.rb +21 -0
- data/spec/konstant/runner_spec.rb +14 -0
- data/spec/konstant_spec.rb +23 -0
- data/spec/spec_helper.rb +27 -0
- metadata +208 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: effe897e9f439446faa514383ab12669c1c876e3
|
|
4
|
+
data.tar.gz: 0098fb81a4dd80eb3f3963f7b2074015e2967bb2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 19a2645f44d5428c8145eb804358ca4c09aff2ee08be8bd730f7a5fa8e95eb2187fb27fd41fb1e2972952a0b34c02ad4d02c16c00928e5f1184273eebeac41ce
|
|
7
|
+
data.tar.gz: aa4fc7a3adbaea16385bfa6b6acfffea7a472b265c64ab024ecf876c750e0dd35690def33c31ab3cc3084e8fa7f81b909b5a4ba46760397e2f73597073631a34
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.0.0-p481
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Moritz Schepp (moritz.schepp@gmail.com)
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Konstant
|
|
2
|
+
|
|
3
|
+
A simple continuous integration server with a web UI, that allows
|
|
4
|
+
you to implement a continuous delivery setup.
|
|
5
|
+
|
|
6
|
+
Konstant is built with ruby and comes as a ruby gem.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Just install the gem like this
|
|
11
|
+
|
|
12
|
+
$ gem install konstant
|
|
13
|
+
|
|
14
|
+
This will provide the `konstant` executable.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Setting up the data directory
|
|
19
|
+
|
|
20
|
+
$ mkdir ci
|
|
21
|
+
$ cd ci
|
|
22
|
+
$ konstant init
|
|
23
|
+
|
|
24
|
+
This will create an empty projects folder and a sample konstant.js config
|
|
25
|
+
file within `ci`. The config file contains reasonable defaults for you to get
|
|
26
|
+
started with.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Running the server
|
|
30
|
+
|
|
31
|
+
The konstant server can be instructed to provide the web UI, the actual build
|
|
32
|
+
scheduler or both. The server has to be run from within the directory containing
|
|
33
|
+
`konstant.js`
|
|
34
|
+
|
|
35
|
+
$ cd ci
|
|
36
|
+
$ konstant run -w # provide the web UI (default http://0.0.0.0:9105)
|
|
37
|
+
$ konstant run -s # provide the CI scheduler
|
|
38
|
+
$ konstant run -w -s # provide both
|
|
39
|
+
|
|
40
|
+
run `konstant --help` for some additional options.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Adding projects
|
|
44
|
+
|
|
45
|
+
Adding projects is done by adding subdirectories under the `ci/projects` folder.
|
|
46
|
+
Bash scripts within those subdirectories define how a project is to be built,
|
|
47
|
+
deployed and cleaned up. A generator is provided to quickly create new projects:
|
|
48
|
+
|
|
49
|
+
$ cd ci
|
|
50
|
+
$ konstant generate project my_app
|
|
51
|
+
|
|
52
|
+
this will create `ci/projects/my_app` including some sample bash scripts. Modify
|
|
53
|
+
them according to your build scenario.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### The scripts
|
|
57
|
+
|
|
58
|
+
A build is a sequence of jobs:
|
|
59
|
+
|
|
60
|
+
* `build` is always run
|
|
61
|
+
* `deploy` is only run if `build` succeeded
|
|
62
|
+
* `cleanup` is always run
|
|
63
|
+
|
|
64
|
+
Those jobs are represented by bash scripts within each project directory. Only
|
|
65
|
+
the `build` script is required, the other jobs are simply not executed
|
|
66
|
+
if the files are missing.
|
|
67
|
+
|
|
68
|
+
The scripts are required to have the executable bit set. Apart from that, it is
|
|
69
|
+
recommended to have each script start with `#!/bin/bash -e` so that any
|
|
70
|
+
failed command within the script will prevent the execution of any remaining
|
|
71
|
+
commands.
|
|
72
|
+
|
|
73
|
+
When a project is built, the above jobs are executed while status, stdout and
|
|
74
|
+
stderr are recorded within the directory for that build. Build directories are
|
|
75
|
+
kept under `ci/projects/my_app/builds` and are named according to the timestamp
|
|
76
|
+
when the build was requested.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Triggering builds
|
|
80
|
+
|
|
81
|
+
Once the CI scheduler is up and running, building can be triggered in three
|
|
82
|
+
ways:
|
|
83
|
+
|
|
84
|
+
* click a button on the web UI
|
|
85
|
+
* create the file `ci/projects/my_app/run.txt`
|
|
86
|
+
* make an http request to `/projects/my_app/build` (any http verb works)
|
|
87
|
+
|
|
88
|
+
You might find the last two ways useful to automate builds after git pushes.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Sample project
|
|
92
|
+
|
|
93
|
+
For example, to test the
|
|
94
|
+
`carrierwave_backgrounder` ruby gem, you could
|
|
95
|
+
|
|
96
|
+
$ cd ci/projects/carrierwave_backgrounder
|
|
97
|
+
$ git clone https://github.com/lardawge/carrierwave_backgrounder.git src
|
|
98
|
+
|
|
99
|
+
And insert the following code into `ci/projects/carrierwave_backgrounder/build`
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
#!/bin/bash -e
|
|
103
|
+
|
|
104
|
+
cd $KONSTANT_PROJECT_ROOT/src
|
|
105
|
+
git pull
|
|
106
|
+
|
|
107
|
+
bundle install --path=$KONSTANT_PROJECT_ROOT/bundle --quiet
|
|
108
|
+
|
|
109
|
+
bundle exec rspec --format progress
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Since we don't want to deploy anything after successful builds and there is
|
|
113
|
+
nothing to cleanup, you might want to
|
|
114
|
+
|
|
115
|
+
$ cd ci/projects/carrierwave_backgrounder/
|
|
116
|
+
$ rm deploy cleanup
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
1. Fork it ( https://github.com/coneda/konstant/fork )
|
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
125
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/konstant
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
4
|
+
|
|
5
|
+
require 'konstant'
|
|
6
|
+
|
|
7
|
+
unless Konstant.env == "production"
|
|
8
|
+
require "debugger"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
cli = Konstant::Cli.new
|
|
12
|
+
cli.parse_options
|
|
13
|
+
command = cli.cli_arguments.first
|
|
14
|
+
|
|
15
|
+
[:INT, :TERM].each do |sig|
|
|
16
|
+
trap sig do
|
|
17
|
+
Konstant.shutdown_handlers.each do |sh|
|
|
18
|
+
sh.call
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
command = "version" if cli.config[:version]
|
|
24
|
+
Konstant.configure "data_dir" => File.expand_path(".")
|
|
25
|
+
|
|
26
|
+
case command
|
|
27
|
+
when "version"
|
|
28
|
+
puts Konstant::VERSION
|
|
29
|
+
when "run"
|
|
30
|
+
Konstant.configure "./konstant.js"
|
|
31
|
+
|
|
32
|
+
require "puma"
|
|
33
|
+
require "rack/handler/puma"
|
|
34
|
+
|
|
35
|
+
threads = []
|
|
36
|
+
|
|
37
|
+
if cli.config[:web]
|
|
38
|
+
threads << Thread.new do
|
|
39
|
+
options = {
|
|
40
|
+
:Host => cli.config[:host],
|
|
41
|
+
:Port => cli.config[:port]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
app = Konstant::Web
|
|
45
|
+
static = Rack::Static.new(app,
|
|
46
|
+
:urls => ["/assets"],
|
|
47
|
+
:root => "#{Konstant.root}/public",
|
|
48
|
+
:index => "index.html"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
Rack::Handler::Puma.run static, options do |server|
|
|
52
|
+
Konstant.shutdown_handlers << Proc.new do
|
|
53
|
+
server.stop
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
sleep 2
|
|
58
|
+
puts "Web server started"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if cli.config[:scheduler]
|
|
62
|
+
threads << Thread.new do
|
|
63
|
+
Konstant::Scheduler.new.run
|
|
64
|
+
end
|
|
65
|
+
puts "Build scheduler started"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
threads.map{|t| t.join}
|
|
69
|
+
when "config"
|
|
70
|
+
Konstant.configure "./konstant.js"
|
|
71
|
+
p Konstant.config
|
|
72
|
+
when "init"
|
|
73
|
+
system "cp -a #{Konstant.root}/data/templates/data_dir/* ."
|
|
74
|
+
when "generate"
|
|
75
|
+
item = cli.cli_arguments[1]
|
|
76
|
+
|
|
77
|
+
case item
|
|
78
|
+
when "project"
|
|
79
|
+
project_id = cli.cli_arguments[2]
|
|
80
|
+
Konstant.configure "./konstant.js"
|
|
81
|
+
system "cp -a #{Konstant.root}/data/templates/project #{Konstant.config['data_dir']}/projects/#{project_id}"
|
|
82
|
+
else
|
|
83
|
+
puts "Generator doesn't exist: '#{item}'"
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
raise "unknown command '#{command}'"
|
|
87
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
/* the amount of builds to keep for each project */
|
|
3
|
+
"builds_to_keep": 50,
|
|
4
|
+
|
|
5
|
+
/* the interval to check for new projects */
|
|
6
|
+
"new_projects_interval": 5,
|
|
7
|
+
|
|
8
|
+
/* the interval to check if a project has to be rebuilt */
|
|
9
|
+
"build_check_interval": 1,
|
|
10
|
+
|
|
11
|
+
/* the sender address for mail notifications */
|
|
12
|
+
"mail_sender": "admin@example.com",
|
|
13
|
+
|
|
14
|
+
/* a list of recipients for notifications on failures and recoveries */
|
|
15
|
+
"notify": []
|
|
16
|
+
}
|
|
File without changes
|
|
File without changes
|
data/konstant.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'konstant/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "konstant"
|
|
8
|
+
spec.version = Konstant::VERSION
|
|
9
|
+
spec.authors = ["Moritz Schepp"]
|
|
10
|
+
spec.email = ["moritz.schepp@gmail.com"]
|
|
11
|
+
spec.summary = "Continous delivery made easy."
|
|
12
|
+
spec.homepage = "https://github.com/coneda/konstant"
|
|
13
|
+
spec.license = "MIT"
|
|
14
|
+
|
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
18
|
+
spec.require_paths = ["lib"]
|
|
19
|
+
|
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
22
|
+
spec.add_development_dependency "rspec"
|
|
23
|
+
spec.add_development_dependency "debugger"
|
|
24
|
+
|
|
25
|
+
spec.add_dependency "json"
|
|
26
|
+
spec.add_dependency "puma"
|
|
27
|
+
spec.add_dependency "mixlib-cli"
|
|
28
|
+
spec.add_dependency "mail"
|
|
29
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
class Konstant::Build
|
|
2
|
+
|
|
3
|
+
def initialize(project, timestamp)
|
|
4
|
+
@project = project
|
|
5
|
+
@timestamp = timestamp
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :project, :timestamp
|
|
9
|
+
|
|
10
|
+
def create
|
|
11
|
+
system "mkdir -p #{path}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def destroy
|
|
15
|
+
system "rm -rf #{path}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def human
|
|
19
|
+
Time.parse(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ok?(task = 'build')
|
|
23
|
+
status(task) == nil ? nil : (status(task) == 0)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def failure?
|
|
27
|
+
!ok?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def path
|
|
31
|
+
"#{project.path}/builds/#{timestamp}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def status(task = 'build')
|
|
35
|
+
File.read("#{path}/#{task}.status").strip.to_i
|
|
36
|
+
rescue Errno::ENOENT => e
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def stdout(task = 'build')
|
|
41
|
+
File.read "#{path}/#{task}.stdout"
|
|
42
|
+
rescue Errno::ENOENT => e
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def stderr(task = 'build')
|
|
47
|
+
File.read "#{path}/#{task}.stderr"
|
|
48
|
+
rescue Errno::ENOENT => e
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def previous
|
|
53
|
+
timestamps = project.build_timestamps
|
|
54
|
+
index = timestamps.index(timestamp)
|
|
55
|
+
if index <= timestamps.size - 1
|
|
56
|
+
project.builds[index + 1]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def as_json(*)
|
|
61
|
+
return {
|
|
62
|
+
"project_id" => project.id,
|
|
63
|
+
"timestamp" => timestamp,
|
|
64
|
+
"human" => human,
|
|
65
|
+
"stdout" => stdout,
|
|
66
|
+
"stderr" => stderr,
|
|
67
|
+
"status" => status,
|
|
68
|
+
"ok" => ok?,
|
|
69
|
+
"deploy" => {
|
|
70
|
+
"stdout" => stdout('deploy'),
|
|
71
|
+
"stderr" => stderr('deploy'),
|
|
72
|
+
"status" => status('deploy')
|
|
73
|
+
},
|
|
74
|
+
"cleanup" => {
|
|
75
|
+
"stdout" => stdout('cleanup'),
|
|
76
|
+
"stderr" => stderr('cleanup'),
|
|
77
|
+
"status" => status('cleanup')
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def to_json(*args)
|
|
83
|
+
as_json.to_json(*args)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
class Konstant::Builder
|
|
2
|
+
|
|
3
|
+
def initialize(project)
|
|
4
|
+
@project = project
|
|
5
|
+
@timestamp = Time.now.strftime("%Y%m%d%H%M%S")
|
|
6
|
+
@new_build = Konstant::Build.new project, timestamp
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_reader :project, :timestamp, :new_build
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
Konstant.logger.info "building project '#{project.id}'"
|
|
13
|
+
|
|
14
|
+
if build
|
|
15
|
+
if previous_build_failed?
|
|
16
|
+
Konstant.logger.info "project '#{project.id}' recovered"
|
|
17
|
+
notify :recovery
|
|
18
|
+
else
|
|
19
|
+
Konstant.logger.info "project '#{project.id}' built successfully"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Konstant.logger.info "deploying project '#{project.id}'"
|
|
23
|
+
unless deploy
|
|
24
|
+
notify :deploy_failed
|
|
25
|
+
end
|
|
26
|
+
Konstant.logger.info "project '#{project.id}' deployed"
|
|
27
|
+
else
|
|
28
|
+
Konstant.logger.info "project '#{project.id}' failed to build"
|
|
29
|
+
notify :failure
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Konstant.logger.info "cleaning up project '#{project.id}'"
|
|
33
|
+
unless cleanup
|
|
34
|
+
notify :cleanup_failed
|
|
35
|
+
end
|
|
36
|
+
Konstant.logger.info "project '#{project.id}' cleaned up"
|
|
37
|
+
|
|
38
|
+
symlink
|
|
39
|
+
Konstant.logger.info "finished building project '#{project.id}'"
|
|
40
|
+
|
|
41
|
+
cleanup_old_builds
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def build
|
|
45
|
+
Konstant::Runner.new(new_build, "build").run
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def deploy
|
|
49
|
+
Konstant::Runner.new(new_build, "deploy").run
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def cleanup
|
|
53
|
+
Konstant::Runner.new(new_build, "cleanup").run
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def cleanup_old_builds
|
|
57
|
+
builds = project.builds
|
|
58
|
+
limit = Konstant.config["builds_to_keep"]
|
|
59
|
+
|
|
60
|
+
if builds.size > limit
|
|
61
|
+
Konstant.logger.info "removing #{builds.size - limit} build(s) from project '#{project.id}'"
|
|
62
|
+
builds[limit..-1].each do |build|
|
|
63
|
+
build.destroy
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def symlink
|
|
69
|
+
system "ln -sfn #{new_build.path} #{project.path}/current"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def notify(message)
|
|
73
|
+
unless Konstant.config["notify"].empty?
|
|
74
|
+
Mail.deliver do
|
|
75
|
+
from Konstant.config["mail_sender"]
|
|
76
|
+
to Konstant.config["notify"]
|
|
77
|
+
|
|
78
|
+
case message
|
|
79
|
+
when :failure
|
|
80
|
+
subject "Konstant: Project failed: #{project.id}"
|
|
81
|
+
when :recovery
|
|
82
|
+
subject "Konstant: Project recovered: #{project.id}"
|
|
83
|
+
when :cleanup_failed
|
|
84
|
+
subject "Konstant: Project could not be cleaned up: #{project.id}"
|
|
85
|
+
when :deploy_failed
|
|
86
|
+
subject "Konstant: Project could not be deployed: #{project.id}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def build_status
|
|
93
|
+
new_build.status
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def build_stdout
|
|
97
|
+
new_build.stdout
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_stderr
|
|
101
|
+
new_build.stderr
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def previous_build_failed?
|
|
105
|
+
new_build.previous ? new_build.previous.failure? : false
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
data/lib/konstant/cli.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require "mixlib/cli"
|
|
2
|
+
|
|
3
|
+
class Konstant::Cli
|
|
4
|
+
|
|
5
|
+
include Mixlib::CLI
|
|
6
|
+
|
|
7
|
+
option(:web,
|
|
8
|
+
:short => "-w",
|
|
9
|
+
:long => "--web",
|
|
10
|
+
:default => false
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
option(:scheduler,
|
|
14
|
+
:short => "-s",
|
|
15
|
+
:long => "--scheduler",
|
|
16
|
+
:default => false
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
option(:host,
|
|
20
|
+
:short => "-h HOST",
|
|
21
|
+
:long => "--host HOST",
|
|
22
|
+
:default => "0.0.0.0"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
option(:port,
|
|
26
|
+
:short => "-p PORT",
|
|
27
|
+
:long => "--port PORT",
|
|
28
|
+
:default => "9105"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
option(:version,
|
|
32
|
+
:short => "-v",
|
|
33
|
+
:long => "--version",
|
|
34
|
+
:default => false
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class Konstant::Project
|
|
2
|
+
|
|
3
|
+
def initialize(id)
|
|
4
|
+
@id = id
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
attr_reader :id
|
|
8
|
+
|
|
9
|
+
def self.all
|
|
10
|
+
Dir["#{Konstant.config['data_dir']}/projects/*"].map do |path|
|
|
11
|
+
new path.split('/').last
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build!
|
|
16
|
+
system "touch #{path}/run.txt"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def building?
|
|
20
|
+
File.exists? "#{path}/running.txt"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def path
|
|
24
|
+
"#{Konstant.config['data_dir']}/projects/#{id}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build_timestamps
|
|
28
|
+
Dir["#{path}/builds/*"].map do |path|
|
|
29
|
+
path.split('/').last
|
|
30
|
+
end.sort.reverse
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def builds
|
|
34
|
+
build_timestamps.map do |ts|
|
|
35
|
+
Konstant::Build.new self, ts
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def last_build
|
|
40
|
+
if ts = build_timestamps.first
|
|
41
|
+
Konstant::Build.new self, ts
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ok?(task = 'build')
|
|
46
|
+
last_build && last_build.ok?(task)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def status(task = 'build')
|
|
50
|
+
last_build ? last_build.status(task) : nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def stdout(task = 'build')
|
|
54
|
+
last_build ? last_build.stdout(task) : nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def stderr(task = 'build')
|
|
58
|
+
last_build ? last_build.stderr(task) : nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def as_json(*)
|
|
62
|
+
return {
|
|
63
|
+
"id" => id,
|
|
64
|
+
"ok" => ok?,
|
|
65
|
+
"deploy_ok" => ok?('deploy'),
|
|
66
|
+
"cleanup_ok" => ok?('cleanup'),
|
|
67
|
+
"building" => building?
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_json(*args)
|
|
72
|
+
as_json.to_json(*args)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|